GHSA-f36j-f34j-h3rx
/ CVE-2026-77521 を再現する、自己完結型の無害なラボです。MaxKB(オープンソースのエンタープライズ AI アシスタント / RAG プラットフォーム)では、ツール、MCP ツール、スキル、またはサブアプリケーションを持つあらゆるアシスタントに、シェルの execute ツールが自動注入されます。このツールは人間による承認ゲートの背後にありません。そのため、プロンプトインジェクション(チャットまたは取り込まれたドキュメントから)がシェルに到達します。サンドボックスがそれを封じ込めるはずでしたが、shell=True の文字列によってメタ文字が脱出できてしまいました。
| アドバイザリ | GHSA-f36j-f34j-h3rx |
| CVE | CVE-2026-77521 |
| プロジェクト | 1Panel-dev/MaxKB |
| 影響を受けるバージョン | < 2.10.5-lts |
| 修正済み | 2.10.5-lts(コミット 594f50f)— 部分的、以下を参照 |
| CVSS | 10.0 CRITICAL (AV:N/AC:L/PR:N/UI:N/S:C/C:H/I:H/A:H) |
| 弱点 | CWE-78(OS コマンドインジェクション) · CWE-250(不要な権限) · CWE-749(危険なメソッドの露出) |
これは、教育および防御目的のために、修正済みで公開開示された脆弱性を再現するものです。完全にローカルで無害に動作します:
id、PoC が削除するマーカーファイルの書き込み)のみを実行します。実際の gosu/サンドボックス/root は関与しません — 権限降下ラッパーは不活性な env マーカーに置き換えられているため、デモはどこでも実行できます。何らかの機能が付与された MaxKB アシスタントは、SandboxShellBackend を備えた deepagents 上に構築されます。deepagents はシェルの execute ツール(および read_file/write_file/…)を自動注入し、MaxKB は excluded_tools を使用しないため、execute は常に存在します。人間の承認が必要なものを決定する interrupt_on 設定は {"write_file": False, "read_file": False, "edit_file": False} です:execute が含まれていないため、承認なしで実行されます。 したがって、モデルを誘導できるあらゆるテキスト(チャットメッセージ、または RAG パイプラインが取り込む汚染されたドキュメント)が、エージェントにシェルコマンドを実行させることができます。ソースインストールでは SANDBOX がデフォルトでオフになるため、コマンドはアプリユーザーとして実行されます。公式(root)コンテナでは、サンドボックスラッパーが shell=True の文字列であったため、;/>/$() が gosu の外で root として実行されました。
interrupt_on では、注入された execute 呼び出しが承認なしで実行されます。"execute": True を追加するとゲートされます。→ poc/01_missing_hitl_gate.py;+リダイレクトが単一文字列の gosu プレフィックスを脱出します。2.10.5-lts の _build_sandbox_command() が再クォートすることで無効化されます。→ poc/02_sandbox_escape.pyexecute を呼び出します(クリーンなドキュメントでは呼び出しません)。→ poc/03_real_llm.py同梱されている 2.10.5-lts パッチ(コミット 594f50f)は
サンドボックスエスケープのみを強化する — これは _build_sandbox_command() を追加し、
シェル演算子で分割し、各トークンを shlex.quote で再クォートし、
各単純コマンドを gosu プレフィックスでラップする。v2.10.5-lts ソース
に対して検証したところ、エージェントコアは変更されていない: interrupt_on は依然として execute を省略し、
バックエンドは依然として SandboxShellBackend であり、SANDBOX は依然として 0 がデフォルトである。したがって
修正後も、プロンプトインジェクションされた execute は人間の承認なしに実行される —
内側の壁は強化されたが、ゲートは開いたままだった。PoC 1 は
ベンダーが提供しなかった推奨の緩和策(execute をゲートする)を実証する。
PoC 1/2 に依存関係は不要(Python 3.9+):
./run.sh # all three (PoC 3 skips without an endpoint)
python3 poc/01_missing_hitl_gate.py # missing approval gate
python3 poc/02_sandbox_escape.py # metacharacter sandbox escape
任意の OpenAI 互換エンドポイント(セルフホストまたはホスト型のオープンモデル)。例(Groq):
export OPENAI_BASE_URL=https://api.groq.com/openai/v1
export OPENAI_API_KEY=$GROQ_API_KEY # read from env only; never logged
MODEL="openai/gpt-oss-20b" python3 poc/03_real_llm.py
TLS検査プロキシの背後では、警告付きで検証なしの再試行を行います
(強制するには INSECURE_SSL=1)。エンドポイントが設定されていない場合はクリーンにスキップします。
| パス | 内容 |
|---|---|
sandbox_shell.py | MaxKBの execute() コマンド構築の無害なモデル — 脆弱な文字列 vs パッチ適用済みの _build_sandbox_command() |
agent_sim.py | deepagents の interrupt_on 人間承認ゲートの最小モデル |
payloads/poisoned-document.md | 攻撃者によって汚染されたKBドキュメント(間接インジェクション) |
poc/01_missing_hitl_gate.py | 注入された execute が承認なしで実行される;ゲートによりブロックされる |
poc/02_sandbox_escape.py | メタ文字が gosu プレフィックスを脱出する;2.10.5 のパーサーはそれらを封じ込める |
poc/03_real_llm.py | 実際のモデルが汚染ドキュメントから execute を呼び出す(クリーン vs 汚染) |
DEMO.md / demo.sh | プレゼンター用ランブックとペース配分されたデモドライバー |
assets/attack-flow.{svg,png} | 攻撃フロー図(ブログのヒーロー画像) |
assets/poc3-groq-sample.txt | 記録された PoC 3 の出力(デモのフォールバック) |