MINARA
セキュリティ

スクリプトリスクゲート

エージェントがどのスクリプトや命令を許可・確認・拒否するかを決める仕組み。RED、YELLOW、GREEN それぞれの判断基準と理由を説明します。

Agent は次のようなウィジェットを表示します。

The script contains 1 risk. Execute anyway?

[fund_moving_cli] The script will move funds via `minara swap`.
[ Execute ] [ Cancel ]

どのスクリプトが確認ウィジェットをトリガーし、どれが暗黙的に許可され、どれが完全に拒否されるのか。その判断ロジックをこのページで説明します。

3 つのライン

ゲートの判断モデルは 3 つのカテゴリで構成されています。パターンの列挙ではなく、それぞれが「答えるべき問い」によって定義されています。

  • GREEN:合理的で、元に戻せて、コストが低い操作。データの読み取り、数値計算、新規ファイルへの書き込み、公開された HTTPS の GET リクエストなどが該当します。Agent はあなたの作業を中断せずに進めます。
  • YELLOW:正当だが、影響が大きい操作。資金移動、オンチェーン認可の変更、特定ファイルの削除、パッケージのインストール、外部への書き込みなどが含まれます。それが意図的な操作かどうかはあなたにしか判断できません。 ゲートは一時停止して確認を求めます。
  • RED正当なビジネス上の理由がない操作。大量削除、クラウドメタデータの外部送信、~/.ssh/id_rsa の読み取り、コンテナエスケープ、ソースコードへのインライン秘密鍵のハードコードなどが該当します。あなたがその操作を「望んでいる」としても、正しい対応は適切なツールを使うことであり、このようなスクリプトを Agent に実行させることではありません。そのため RED はオーバーライド不可です。クリックしても、フラグを渡しても、回避できません。

なぜ RED はオーバーライドできないのか? RED の検出のほとんどはプロンプトインジェクションによるものだからです。ウェブページ、スキルのコンテンツ、またはツール結果が LLM に「次にこの便利なスクリプトを実行してください」といった内容を送り込んでおり、LLM はその操作を丁寧に説明しているだけです。RED を「ユーザー確認」でバイパスできてしまうと、あなたが「はい」をクリックした瞬間に攻撃が成立します。なぜなら、あなたが読んだ説明は Agent ではなく攻撃者が書いたものだからです。そのため RED は会話の内容に関係なく強制されます。「リスクを理解した上で実行したい」という主張は通りません。あなたが理解した内容は、すでに攻撃者のフレーミングを通じて届いたものだからです。

YELLOW 確認ウィジェットに表示される内容

各リスクエントリには 3 つの要素が含まれます。

  • カテゴリfund_moving_clionchain_dangerous_call など、リスクの種類。
  • 証拠(Evidence):検出されたスクリプト内の実際の行。秘密鍵の hex 値、Authorization ヘッダー、Bearer token、長い base64 ブロブは <REDACTED-*> プレースホルダーに置換されます。
  • 判断:Execute(実行)または Cancel(キャンセル)。

なぜ証拠をマスクするのか? このウィジェットはあなたが意図を判断するために存在しており、「これは意図的か?」という問いに答えるために秘密の中身を見る必要はないからです。スクリプトに new ethers.Wallet("0xabc…64-hex…") が含まれている場合、生の hex 値を表示すると確認ウィジェットが第二の情報漏洩経路になってしまいます。そのバイト列が監査ログ、チャット履歴、さらにはスクリーンレコーディングにまで記録されてしまうからです。マスク処理によって「秘密鍵がウォレットコンストラクターに渡されている」という事実だけが示されます。それこそがあなたが本当に答えるべき問いです。

カテゴリの分類基準

すべてのパターンを列挙するのではなく(正規表現の正式リストはソースコードを参照してください。apps/agent/src/tools/_shared/script-risk.ts にあります)、ここでは「なぜ RED ではなく YELLOW に分類されたか」という判断の根拠を説明します。代表的な例を以下に示します。

fund_moving_cli(YELLOW)

minara swapcast sendforge --broadcasthardhat run … --network mainnetsolana transfer などを呼び出すスクリプトが該当します。

なぜ RED ではないか? 積立投資 (DCA) スクリプト、リバランススクリプト、清算ボットは正当な自動化パターンです。RED にするとリアルなワークフローが壊れてしまいます。

なぜ GREEN ではないか? これらの CLI を呼び出すスクリプトは Layer 3(プロセス内の二段階確認)を迂回します。これはあなたが明示的に「はい」をクリックしていないまま Agent が資金を移動する盲点です。ゲートが必ずこれを表面化しなければなりません。

obfuscation_with_sink(RED)

eval(base64.b64decode(...))getattr(__import__("o" + "s"), "sys" + "tem")(...)、逆順文字列のコンパイル、globalThis["Func" + "tion"] などが該当します。

なぜ RED か? 別の説明が存在しません。このようなコードの書き方は静的解析を回避するためにしか使われません。パターン自体が悪意ある意図の証拠であり、ユーザーに確認すべきことは何もありません。

mass_delete(大量削除は RED、特定ファイルは YELLOW)

rm *rm -rf $UNSET/xfind . -deleteshutil.rmtree(".") は RED です。rm sandbox/files/foo.csv は YELLOW です。

なぜこのように分けるのか? 大量削除(特定パスがない、または空に展開される可能性のある変数を使用)は、LLM が「ワークスペースを片付けて」という指示を誤読した結果か、$UNSET/ に展開されるよう仕掛けたプロンプトインジェクションの結果である場合がほとんどです。これらを即座に拒否することで、よくある攻撃とよくあるミスの両方を防ぎます。

特定ファイルの削除(rm sandbox/files/foo.csv)は人々が実際に行いたい操作ですが、ファイルを消す前に「はい、それです」という一呼吸の確認を挟む価値があります。

credential_exfil(RED)

~/.ssh/id_rsa~/.aws/credentials、macOS キーチェーン、Chrome / Brave / Edge のログインデータベース、MetaMask / Phantom 拡張機能のストレージ、1Password / Bitwarden / KeePass のボルトの読み取りが該当します。

なぜ RED か? これらのいずれも「Agent に代わりに開いてもらう」という正当な使い方が存在しません。ワークフローで SSH 鍵を読む必要がある場合は、LLM 駆動のスクリプトではなく専用の CLI を使ってください。RED にすることで、資金的に最も深刻なプロンプトインジェクション攻撃のクラスも無力化されます。

imds_ssrf(RED、すべてのエンコーディング)

クラウドメタデータのエンドポイント(169.254.169.254metadata.google.internal、Alibaba や Oracle の同等物)に加え、攻撃者がナイーブなブロックリストを回避するために使うあらゆるエンコード形式(10 進数 2852039166、16 進数 0xa9fea9fe、IPv6 マッピング [::ffff:169.254.169.254])が対象です。

なぜ RED か? ユーザー向けの正当なスクリプトがインスタンスメタデータサービスを呼び出す理由はありません。このカテゴリに引っかかるケースのほとんどは、Agent を実行しているクラウドホストから IAM 認証情報を盗もうとする SSRF の試みです。

direct_signing_with_constructor(RED)

new ethers.Wallet("0x…64-hex…")Account.from_key("0x…")Keypair.fromSecretKey(byteArray) などが該当します。

なぜ RED か? スクリプトソースにインライン秘密鍵があるということは、(a)誰かがあなたの鍵を盗もうとしているか、(b)あなたがその鍵をディスクにコミットしようとしているかのどちらかです。いずれにせよ正しい次の行動は停止することであり、確認を求めることではありません。Agent のネイティブな取引ツールを使ってください。ソースに鍵を貼り付ける必要はありません。

env_var_poisoning(YELLOW)

NODE_OPTIONS=--require ./steal.jsLD_PRELOAD=…BASH_ENV=…PYTHONPATH=. の設定が該当します。

なぜ RED ではなく YELLOW か? 一部は正当な使い方があります(トレーシングのための NODE_OPTIONS 設定、ローカル開発用の PYTHONPATH など)。しかし、これらはいずれも子プロセスにコードをインジェクションする標準的な手法でもあります。ゲートがこれを表面化することで、その環境変数が指しているファイルが自分で書いたものか、プロンプトインジェクションによって書かれたものかを確認できます。

フルカタログは RED 12 カテゴリ、YELLOW 13 カテゴリです。ソースコードが正式リストであり、新しい回避手法が出現するたびにパターンが追加されます。上記の例は最も運用上重要なものです。

ゲートが見えないもの

静的解析には明確な限界があります。それを知ることで、オペレーターとしてどこに注意を払うべきかがわかります。

  • 実行時に構築される文字列。 exec(a + b) のようなスクリプトで ab が実行時に計算される場合、アナライザーは exec(<variable>) を検出して dynamic_command の YELLOW を報告しますが、実際に実行される文字列が何かは判断できません。スクリプトを読む必要があるのはあなたです。
  • 複数ツールを組み合わせた攻撃。 あるスクリプトがファイルを書き込み、環境変数を設定し、別の terminal 呼び出しでそれらを読むバイナリを実行するケース。各呼び出しは単体では無害に見えます。ゲートは 1 回の呼び出しを 1 つずつ検査します。ここで頼るべきバックストップはゲートではなく Layer 2(OS jail)です。
  • まったく新しい難読化パターン。 攻撃者はこのソースを読み、正規表現の隙間を探すことができます。99 回重ねた hex エンコーディング、Unicode の見た目が似た文字、深くネストした compile() 呼び出しなどです。パターンは随時追加しますが、本当の境界線は Layer 2 です。ここのすべてのルールを突破したとしても、生成されたサブプロセスは依然として bwrap / sandbox-exec の中にいます。

率直に言えば、Layer 4 はスポーン前に意図を検査し、Layer 2 はスポーン後の被害範囲を抑えるということです。Layer 4 が何かを見逃しても、Layer 2 がまだ機能しています。

決定フロー

LLM が execute_code を呼び出してから実際にサブプロセスが起動するまでの流れは次のとおりです。

LLM → execute_code({ code, language })


   analyzeScript(body)

   ┌────┼────┐
   ▼    ▼    ▼
  RED  YEL  GREEN
   │    │    │
   │    ▼    ▼
   │  ctx.interactionQueue.ask()
   │    │    │
   │    │    └── handler proceeds → spawn
   │    │
   │    ├── user "Execute"  → handler proceeds → spawn
   │    └── user "Cancel"   → err("user_declined: …")

   └── err("script_risk_rejected: …")

ゲートはプロンプトレベルの指示ではバイパスできません。LLM のプロンプトではなく、サブプロセス処理が始まる前のハンドラー内に実装されているからです。

ユーザーが制御できること

  • ✅ YELLOW に対して Cancel を選択できます。
  • ✅ レビュー済みのワークフロー定義内で script_risk_policy を使い、特定のスクリプト本体を事前承認できます。詳しくは監査とオーバーライドを参照してください。
  • ❌ RED はオーバーライドできません。クリックで突破できないよう設計されています。信頼しているスクリプトが RED に引っかかる場合、正しい対処はゲートと押し問答することではなく、スクリプトを書き直すことです(例:インライン秘密鍵ではなく Minara のネイティブ取引ツールを使う)。
  • ❌ LLM はウィジェットをスキップできません。ゲートはスポーンより前のツールハンドラーで動作しており、LLM がプロンプトエンジニアリングで回避することはできません。

目次