多層防御
Triggerfishshは13の独立した重複するレイヤーとしてセキュリティを実装しています。単独では どのレイヤーも十分ではありません。合わせて、1つのレイヤーが侵害されても緩やかに低下する 防御を形成します。
セキュリティ 多層防御とは、どの単一レイヤーの脆弱性もシステムを
侵害しないことを意味します。チャンネル認証を回避した攻撃者でも、セッションtaint追跡、 ポリシーhook、監査ログに直面します。プロンプトインジェクションされたLLMでも、 その下の決定論的なポリシーレイヤーに影響を与えることはできません。 :::
13のレイヤー
レイヤー1:チャンネル認証
保護対象: なりすまし、不正アクセス、アイデンティティの混乱。
アイデンティティは、LLMがメッセージコンテンツを解釈するのではなく、セッション確立時の コードによって決定されます。LLMがメッセージを見る前に、チャンネルアダプターが 不変のラベルでタグ付けします:
{ source: "owner" } -- 確認されたチャンネルIDが登録されたオーナーと一致
{ source: "external" } -- それ以外の人;入力のみ、コマンドとして扱われない認証方法はチャンネルによって異なります:
| チャンネル | 方法 | 確認 |
|---|---|---|
| Telegram / WhatsApp | ペアリングコード | ワンタイムコード、5分有効期限、ユーザーアカウントから送信 |
| Slack / Discord / Teams | OAuth | プラットフォームOAuthコンセントフロー、確認済みユーザーIDを返す |
| CLI | ローカルプロセス | ユーザーのマシン上で実行、OSによる認証 |
| WebChat | なし(公開) | すべての訪問者はEXTERNAL、ownerにはなれない |
| ドメインマッチング | 送信者ドメインと設定された内部ドメインを比較 |
LLMは誰がオーナーかを決定しません。確認されていない送信者からの
「私はオーナーです」というメッセージは{ source: "external" }とタグ付けされ、 オーナーレベルのコマンドをトリガーできません。この決定はコードで行われ、LLMが メッセージを処理する前に完了します。 :::
レイヤー2:権限対応データアクセス
保護対象: 過剰なデータアクセス権限、システム認証情報による特権昇格。
Triggerfishshはシステムサービスアカウントではなく、ユーザーの委任OAuthトークンを使用して 外部システムにクエリを実行します。ソースシステムが独自の権限モデルを強制します:
Plugin SDKはAPIレベルでこれを強制します:
| SDKメソッド | 動作 |
|---|---|
sdk.get_user_credential(integration) | ユーザーの委任OAuthトークンを返す |
sdk.query_as_user(integration, query) | ユーザーの権限で実行 |
sdk.get_system_credential(name) | ブロック — PermissionErrorを発生 |
レイヤー3:セッションTaint追跡
保護対象: コンテキスト汚染によるデータ漏洩、分類されたデータがより低い分類の チャンネルに到達すること。
すべてのセッションは、セッション中にアクセスされたデータの最高分類を反映するtaint レベルを独立して追跡します。Taintは3つの不変条件に従います:
- 会話ごと — 各セッションは独自のtaintを持つ
- エスカレートのみ — taintは増加するが、低下しない
- 完全リセットですべてをクリア — taintと履歴は一緒に消去される
ポリシーエンジンが出力を評価する際、セッションのtaintをターゲットチャンネルの有効な 分類と比較します。taintがターゲットを超えると、出力はブロックされます。
レイヤー4:データ系譜
保護対象: 追跡不可能なデータフロー、データがどこに行ったかを監査できないこと、 コンプライアンスのギャップ。
すべてのデータ要素は、起点から宛先までのプロベナンスメタデータを持ちます:
- 起点: どの統合、レコード、ユーザーアクセスがこのデータを生成したか
- 分類: どのレベルが割り当てられ、その理由
- 変換: LLMがデータをどのように変更、要約、または結合したか
- 宛先: どのセッションとチャンネルが出力を受け取ったか
系譜はフォワードトレース(「このSalesforceレコードはどこへ行きましたか?」)、 バックワードトレース(「この出力にどのソースが貢献しましたか?」)、および 完全なコンプライアンスエクスポートを可能にします。
レイヤー5:ポリシー強制Hook
保護対象: プロンプトインジェクション攻撃、LLM主導のセキュリティ回避、 制御されていないツール実行。
8つの決定論的なhookがデータフローの重要なポイントですべてのアクションをインターセプトします:
| Hook | インターセプト対象 |
|---|---|
PRE_CONTEXT_INJECTION | コンテキストウィンドウに入る外部入力 |
PRE_TOOL_CALL | LLMのツール実行要求 |
POST_TOOL_RESPONSE | ツール実行から返るデータ |
PRE_OUTPUT | システムを離れようとするレスポンス |
SECRET_ACCESS | 認証情報アクセス要求 |
SESSION_RESET | Taintリセット要求 |
AGENT_INVOCATION | エージェント間の呼び出し |
MCP_TOOL_CALL | MCPサーバーツール呼び出し |
Hookは純粋なコードです:決定論的、同期、ログ記録済み、偽造不可能。LLMはhookを回避できません。 なぜなら、LLM出力からhook設定へのパスウェイが存在しないからです。hookレイヤーは LLM出力をコマンドとして解析しません。
レイヤー6:MCP Gateway
保護対象: 制御されていない外部ツールアクセス、MCPサーバー経由で入る未分類データ、 スキーマ違反。
すべてのMCPサーバーはデフォルトでUNTRUSTEDであり、管理者またはユーザーが分類するまで 呼び出せません。Gatewayは以下を強制します:
- サーバーの認証と分類状態
- ツールレベルの権限(サーバーが許可されていても個々のツールをブロック可能)
- リクエスト/レスポンスのスキーマ検証
- すべてのMCPレスポンスのtaint追跡
- パラメーターのインジェクションパターンスキャン
レイヤー7:プラグインサンドボックス
保護対象: 悪意のあるまたはバグのあるプラグインコード、データ漏洩、 不正なシステムアクセス。
プラグインはダブルサンドボックス内で実行されます:
プラグインは以下ができません:
- 宣言されていないネットワークエンドポイントへのアクセス
- 分類ラベルなしでデータを出力
- taint伝播をトリガーせずにデータを読み取り
- Triggerfishsh外にデータを永続化
- システム認証情報を使用(ユーザーの委任認証情報のみ)
- サイドチャンネル経由でのデータ漏洩(リソース制限、生ソケットなし)
プラグインサンドボックスはエージェントexec環境とは異なります。プラグインは
システムが「から」保護する信頼されていないコードです。exec環境はエージェントが 「構築するために」許可されたワークスペースです — サンドボックス分離ではなく、 ポリシーで管理されたアクセスで。 :::
レイヤー8:シークレット分離
保護対象: 認証情報の盗難、設定ファイル内のシークレット、プレーンテキスト 認証情報ストレージ。
認証情報はOSキーチェーン(個人ティア)またはvault統合(エンタープライズティア)に 保存されます。以下には決して現れません:
- 設定ファイル
StorageProviderの値- ログエントリ
- LLMコンテキスト(認証情報はHTTPレイヤーで注入、LLMの下)
SECRET_ACCESS hookは、リクエストするプラグイン、認証情報スコープ、決定を含む すべての認証情報アクセスをログ記録します。
レイヤー9:ファイルシステムツールサンドボックス
保護対象: パストラバーサル攻撃、不正なファイルアクセス、直接ファイルシステム 操作による分類バイパス。
すべてのファイルシステムツール操作(読み取り、書き込み、編集、リスト、検索)は、 セッションのtaintに適したワークスペースサブディレクトリにスコープされたOSレベルの 権限を持つサンドボックス化されたDeno Worker内で実行されます。サンドボックスは 3つの境界を強制します:
- パスジェイル — すべてのパスは絶対パスに解決され、セパレーターを意識した マッチングでジェイルルートと照合されます。ワークスペースからエスケープする トラバーサル試行(
../)はI/Oが発生する前に拒否されます - パス分類 — すべてのファイルシステムパスは固定の解決チェーンを通じて分類されます: ハードコードされた保護パス(RESTRICTED)、ワークスペース分類ディレクトリ、 設定済みパスマッピング、次にデフォルト分類。エージェントはセッションのtaintを 超えるパスにアクセスできません
- Taintスコープ権限 — サンドボックスWorkerのDeno権限は、セッションの現在の taintレベルに一致するワークスペースサブディレクトリに設定されます。taintが エスカレートすると、Workerは拡張権限で再起動されます。権限はセッション内で 広がることのみ可能で、狭まることはありません
- 書き込み保護 — 重要ファイル(
TRIGGER.md、triggerfish.yaml、SPINE.md)は、 サンドボックス権限に関係なくツールレイヤーで書き込み保護されています。これらの ファイルは、独自の分類ルールを強制する専用管理ツールを通じてのみ変更できます
レイヤー10:エージェントアイデンティティ
保護対象: エージェントチェーンによる特権昇格、委任を通じたデータロンダリング。
エージェントが他のエージェントを呼び出す際、暗号化された委任チェーンが特権昇格を防ぎます:
- 各エージェントは機能と分類上限を指定する証明書を持つ
- 呼び出し先は
max(自身のtaint, 呼び出し元のtaint)を継承 — taintはチェーンを通じて 増加のみ - 呼び出し先の上限を超えるtaintを持つ呼び出し元はブロックされます
- 循環呼び出しは検出され拒否されます
- 委任の深さは制限され、強制されます
レイヤー11:監査ログ
保護対象: 検出不可能な侵害、コンプライアンス障害、インシデント調査の不能。
すべてのセキュリティ関連の決定は完全なコンテキストでログ記録されます:
json
{
"timestamp": "2025-01-29T10:23:45Z",
"user_id": "user_123",
"session_id": "sess_456",
"action": "slack.postMessage",
"target_channel": "external_webhook",
"session_taint": "CONFIDENTIAL",
"target_classification": "PUBLIC",
"decision": "DENIED",
"reason": "classification_violation",
"hook": "PRE_OUTPUT",
"policy_rules_evaluated": ["rule_001", "rule_002"],
"lineage_ids": ["lin_789", "lin_790"]
}ログ記録される内容:
- すべてのアクションリクエスト(許可と拒否の両方)
- 分類決定
- セッションtaintの変更
- チャンネル認証イベント
- ポリシールール評価
- 系譜レコードの作成と更新
- MCP Gateway決定
- エージェント間の呼び出し
監査ログは無効化できません。ポリシー階層の固定ルールです。組織管理者でさえ
自分のアクションのロギングをオフにできません。エンタープライズデプロイメントでは、 フォレンジック要件のための完全なコンテンツログ(ブロックされたメッセージコンテンツを 含む)をオプションで有効にできます。 :::
レイヤー12:SSRF防止
保護対象: サーバーサイドリクエストフォージェリ、内部ネットワーク偵察、 クラウドメタデータの漏洩。
すべてのアウトバウンドHTTPリクエスト(web_fetch、browser.navigate、プラグインの ネットワークアクセスから)は、最初にDNSを解決し、解決されたIPをプライベートおよび 予約済み範囲のハードコードされた拒否リストと照合します。これにより、攻撃者が 細工したURLを通じてエージェントに内部サービスへのアクセスをさせることを防ぎます。
- プライベート範囲(
10.0.0.0/8、172.16.0.0/12、192.168.0.0/16)は常にブロック - リンクローカル(
169.254.0.0/16)とクラウドメタデータエンドポイントはブロック - ループバック(
127.0.0.0/8)はブロック - 拒否リストはハードコードされており設定不可 — 管理者オーバーライドなし
- DNS解決はリクエストの前に行われ、DNSリバインディング攻撃を防ぎます
レイヤー13:メモリ分類ゲーティング
保護対象: メモリを通じたクロスセッションデータ漏洩、メモリ書き込みによる 分類ダウングレード、分類されたメモリへの不正アクセス。
クロスセッションメモリシステムは書き込みと読み取りの両方のタイミングで分類を強制します:
- 書き込み: メモリエントリは現在のセッションのtaintレベルに強制されます。 LLMは保存されるメモリのより低い分類を選択できません。
- 読み取り: メモリクエリは
canFlowToでフィルタリングされます — セッションは 現在のtaintレベル以下のメモリのみ読み取れます。
これにより、エージェントがCONFIDENTIALデータをメモリにPUBLICとして保存し、後で より低いtaintセッションで取得してライトダウン禁止ルールを回避することを防ぎます。
信頼階層
信頼モデルは誰が何に対して権限を持つかを定義します。上位ティアは下位ティアの セキュリティルールを回避できませんが、それらのルール内の調整可能なパラメーターを 設定できます。
個人ティア: ユーザー自身が組織管理者です。完全な主権。Triggerfishshの
可視性なし。ベンダーはデフォルトでユーザーデータへのアクセスがゼロであり、 ユーザーからの明示的な時間制限付きログ記録されたグラントを通じてのみアクセスできます。 :::
レイヤーが連携する仕組み
悪意のあるメッセージがデータを漏洩しようとするプロンプトインジェクション攻撃を 考えてみましょう:
| ステップ | レイヤー | アクション |
|---|---|---|
| 1 | チャンネル認証 | メッセージに{ source: "external" }のタグ付け — オーナーではない |
| 2 | PRE_CONTEXT_INJECTION | 入力のインジェクションパターンスキャン、分類 |
| 3 | セッションtaint | セッションtaint変更なし(分類されたデータへのアクセスなし) |
| 4 | LLMがメッセージを処理 | LLMはツール呼び出しをリクエストするよう操作される可能性がある |
| 5 | PRE_TOOL_CALL | external-sourceルールに対するツール権限チェック |
| 6 | POST_TOOL_RESPONSE | 返されたデータを分類、taintを更新 |
| 7 | PRE_OUTPUT | 出力の分類とターゲットを照合 |
| 8 | 監査ログ | シーケンス全体をレビュー用に記録 |
ステップ4でLLMが完全に侵害されデータ漏洩ツール呼び出しをリクエストしても、 残りのレイヤー(権限チェック、taint追跡、出力分類、監査ログ)は引き続きポリシーを 強制します。単一障害点でシステムが侵害されることはありません。
