oauth-auditor について
oauth-auditorは、MCPサーバーのOAuth認可コードを監査する開発者向けMCPサーバーです。指定されたOAuth 2.1のアンチパターンを検出し、CI/CD向けにSARIFを出力できます。
主な機能
- 016種類のOAuthアンチパターンを検出
- 02ソースファイルとディレクトリを検査
- 03SARIF 2.1.0形式で出力
- 04guardbee.ymlによる設定
活用シーン
- 01リリース前のMCPサーバー認可コードの確認
- 02CI/CDへのOAuthチェックの追加
- 03コード断片やファイルの認可リスク検査
MCP 対応
テキスト、ファイル、ディレクトリのスキャンと、対応パターンの一覧表示を行うMCPツールを提供します。コードスキャンと稼働中エンドポイントのプローブにはコマンドラインも利用できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
4掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| label | string | いいえ | 検出結果に表示する任意のラベル(例:ファイル名) |
| content | string | はい | スキャンするコードの内容 |
詳細
@guardbee/mcp-oauth-auditor
🇬🇧 English | 🇹🇷 Türkçe | 🇨🇳 中文 | 🇯🇵 日本語 | 🇰🇷 한국어 | 🇧🇷 Português | 🇪🇸 Español | 🇩🇪 Deutsch
MCP(Model Context Protocol)サーバー自身の認可コードをスキャンし、MCP 仕様の「セキュリティに関する考慮事項」セクションで明示されているOAuth 2.1 のアンチパターンを検出する MCP サーバーです。
MCP 仕様はこれを曖昧なままにしていません。OAuth リソースサーバーとして動作するサーバーにおける認可の主な失敗パターンとして、トークンパススルー(クライアントのトークンを交換やスコープの再設定をせず、そのまま下流 API に転送すること)と、オーディエンス検証の欠如(aud クレームがこのサーバー向けに発行されていないトークンを受け入れること)を明確に挙げています。このパッケージは、まさにこの 2 つに加え、同じカテゴリーに属する関連アンチパターンを 3 つ検査します。
テレメトリーはデフォルトでオフです。
GUARDBEE_TELEMETRY=1を設定すると、サーバー、ツール、成功状態、処理時間、ファイルパスなどの短いパラメーター値が送信されます。長い文字列やcontent、token、passwordなどのフィールドはプレースホルダーに置き換えられます。詳細は@guardbee/mcp-telemetryをご覧ください。
Claude ──► oauth-auditor ──► Your MCP server's auth code
│
├─ token-passthrough (client's token forwarded unchanged downstream)
├─ token-validation (jwt.verify() with no audience check)
├─ discovery-ssrf (OAuth/OIDC discovery URL built from client input)
├─ pkce (authorization request missing code_challenge)
├─ redirect-validation (redirect_uri checked with startsWith/includes, not exact match)
└─ secrets-exposure (hardcoded client_secret)
この 2 つを特に取り上げる理由
トークンパススルーが問題となるのは、クライアントがこのサーバーに提示したトークンは、このサーバー向けにスコープとオーディエンスが設定されており、サーバー自身のツールハンドラーが次に呼び出す下流 API 向けではないためです。トークンをそのまま転送すると、下流サービスは自らが発行したのではない認証情報を信頼することになります。その根拠となるのは、元のトークン発行者が承認していないサーバー側の判断です。
オーディエンス検証の欠如は、逆方向から見た同じ失敗です。jwt.verify(token, key) はトークンの署名が有効であることを確認しますが、誰に向けて発行されたのかは何も示しません。明示的な audience チェックがなければ、まったく無関係なリソースサーバー向けに発行されたトークンでも、同じ発行者や署名鍵を共有しているというだけで、ここでも検証に成功します。これは、MCP 仕様が警告している典型的な「混乱した代理人」へのすり替えです。
残る 3 つのパターンも、「MCP サーバーの認証コードが信頼すべきでないものを信頼している」という同じテーマに隣接する具体例です。実際に公表された CVE の原因となった形式で、クライアントが指定した入力から OAuth/OIDC のディスカバリー URL を構築すること、完全一致ではなくプレフィックスや部分文字列で redirect_uri を検証すること(オープンリダイレクトの回避)、そして認可リクエストで PKCE が暗黙のうちに欠落することです(OAuth 2.1 ではパブリッククライアントに限らず、無条件に必須です)。
機能
- 6 categories:token-passthrough、token-validation、discovery-ssrf、pkce、redirect-validation、secrets-exposure
- 2 つのチェック(audience 検証の欠如、PKCE の欠如)は、固定の正規表現ではなく、呼び出し箇所付近に存在しないことを調べます。
jwt.verify(...)の呼び出し全体(または認可リクエスト URL の構築)を抽出し、audience:/code_challengeが付近に本当に存在しないことを確認します。たまたま文字列の位置が一致しただけの場合は検出しません。 - SARIF 2.1.0 出力 — CI/CD との統合(GitHub Code Scanning など)
guardbee.ymlによる設定ファイルのサポート- 18 件の単体テスト — 各パターンに肯定シナリオと否定(誤検出)シナリオを用意し、検出結果がゼロになる完全に正しい OAuth フローを 1 件用意しています。開発中に実際の正規表現のバグを発見して修正しました(
]の後にある末尾の\bは、]が単語文字ではないため一致しません。これにより、ヘッダーアクセスのブラケット記法がひそかに見逃されていました)。6 つすべてのアンチパターンを意図的に仕込んだフィクスチャでエンドツーエンド検証を実施し、6 件すべてを検出しました。また、guardbee-mcp モノレポ全体(401 ファイル)に対しても検証し、実際のサードパーティコードでは検出結果がゼロでした。テスト以外で一致したのはスキャナー自身のパターン定義で、正規表現リテラル内の文字列jwt.verify(とドキュメントコメントに含まれる文字列だけであり、実際の脆弱な使用ではありませんでした。
クイックスタート
Claude Desktop / MCP クライアント
{
"mcpServers": {
"guardbee-oauth-auditor": {
"command": "npx",
"args": ["-y", "@guardbee/mcp-oauth-auditor"]
}
}
}
CLI(CI/CD)
npx @guardbee/mcp-oauth-auditor scan ./src --fail-on=high --format=sarif > results.sarif
MCP ツール
| ツール | 説明 |
|---|---|
scan_text | コードスニペットをスキャンします |
scan_file | 単一のファイルをスキャンします |
scan_directory | ディレクトリを再帰的にスキャンします |
list_patterns | カテゴリー別に、サポートされているすべてのパターンを一覧表示します |
検出されるパターン
| カテゴリー | パターン | 深刻度 | OWASP |
|---|---|---|---|
| token-passthrough | token_passthrough_to_downstream | critical | MCP07 |
| token-validation | missing_audience_validation | high | MCP07 |
| discovery-ssrf | oauth_discovery_ssrf | critical | MCP07 |
| pkce | missing_pkce_on_auth_request | high | MCP07 |
| redirect-validation | loose_redirect_uri_validation | high | MCP07 |
| secrets-exposure | hardcoded_oauth_client_secret | high | MCP07 |
| state-handle | predictable_state_handle(+ Python) — Math.random、Date.now、カウンターから生成された state / セッションハンドル | high | MCP07 |
| state-handle | state_handle_not_bound_to_user — ツール引数から取得したハンドルを検索する際、呼び出し元本人のものかどうかを確認していない | medium | MCP07 |
| mix-up | missing_iss_validation — iss を検証せずに認可コードを交換している(RFC 9207) | medium | MCP07 |
| auth-url | auth_url_scheme_not_validated — サーバーから提供された URL をスキームの検証なしで開いている(javascript:、data:、file:) | high | MCP07 |
| auth-url | auth_url_opened_via_shell — URL をシェル経由で open / xdg-open / start に渡している | critical | MCP05 |
| local-exposure | local_http_server_unauthenticated — 認証のない HTTP MCP トランスポート | high | MCP07 |
| local-exposure | missing_host_origin_check — Host / Origin の検証がない(DNS リバインディング) | medium | MCP07 |
| local-exposure | listen_all_interfaces — MCP サーバーが 0.0.0.0 にバインドされている | medium | MCP07 |
Python と Go
言語はファイル拡張子から判定され、Python 固有および Go 固有のルールは、それぞれの言語のファイルに対してのみ実行されます。
- Python(FastAPI / Starlette / Flask、PyJWT、python-jose、authlib):
python_missing_audience_validation(audience=を指定せず、authlib のclaims_optionsにaudもないjwt.decode)、python_audience_verification_disabled("verify_aud": False)、python_token_passthrough_to_downstream(requests/httpx/ クライアント呼び出しでのAuthorizationヘッダーまたはrequest.headers全体の転送)、code_challengeを指定せずに authlib のcreate_authorization_url/authorize_redirectを使う場合のmissing_pkce_on_auth_request、およびディスカバリーの SSRF、リダイレクト、state、0.0.0.0に関するルール。 - Go(golang-jwt / jwx、go-oidc、golang.org/x/oauth2、go-sdk、mcp-go の HTTP トランスポート):
go_missing_audience_validation(jwt.WithAudienceを指定しないjwt.Parse)、go_oidc_client_id_check_skipped、go_token_passthrough_to_downstream(out.Header.Set("Authorization", r.Header.Get("Authorization")))、go_hardcoded_oauth_client_secret、go_loose_redirect_uri_validation(strings.HasPrefix)、go_predictable_state_handle(math/rand、time)、go_oauth_discovery_ssrf、go_auth_url_opened_via_shell、S256ChallengeOptionを指定せずにAuthCodeURLを使う場合のmissing_pkce_on_auth_request、およびListenAndServe(":8080")をlisten_all_interfacesとして検出するルール。 - 両方:
token_passthrough_via_variable— 受信したAuthorizationヘッダーを変数に読み込み、その変数を送信リクエストに設定するケース。
各検出結果は、該当する MCP spec Security Best Practices のセクションにリンクし(SARIF の helpUri)、SARIF タグとして OWASP MCP Top 10 の ID を付与します。新しいルールは、1 ファイルずつを対象にしたヒューリスティックです。別のモジュールで実施されるチェック(認証ミドルウェアや、ヘルパー内の iss 比較など)は検出されません。
ライブプローブ
npx @guardbee/mcp-oauth-auditor probe http://127.0.0.1:3000/mcp
実行中の HTTP MCP エンドポイントに対する読み取り専用チェックです。認証情報なしで initialize に応答するか(probe_unauthenticated_access)、外部の Host(probe_dns_rebinding_host_accepted)または Origin(probe_foreign_origin_accepted)を受け入れるかを確認します。認証情報は送信せず、initialize 以外は呼び出さず、開いたセッションはすべて閉じます。また、--allow-public が指定されていない限り、パブリックアドレスに解決されるホストは拒否します。CLI 専用です。エージェントは MCP ツールを通じて起動できません。
設定(guardbee.yml)
oauth-auditor:
fail-on: high # any | critical | high | medium | none
max-files: 5000
exclude:
- ".test.ts"
制限事項(設計上のもの)
- TypeScript/JavaScript、Python、Go。 それぞれ、一般的なライブラリ向けのルールがあります(上記参照)。その他の言語(Rust、Java、C#、…)やライブラリは、リテラルの
client_secretやresponse_type=codeなど、これらと同じ形式に当てはまる場合にのみ検出されます。 - 完全な OAuth 適合性テストではなく、ヒューリスティックです。 実行中の認可サーバーに対するライブプロトコル適合性チェックではなく、ソースコード内の特定のアンチパターンを検出します。OAuth フローのあらゆる誤実装を検出するわけではなく、MCP 仕様が最も重大なものとして挙げている一部のみを対象とします。
- audience と PKCE の有無に基づくチェックでは、範囲を限定したテキストウィンドウを使用し、実際のパーサーは使いません。 呼び出し箇所から遠く離れた場所でオプションオブジェクトが構築されている
jwt.verify()呼び出し(インラインオブジェクトではなく、変数が渡されるケース)では、audienceが正しくチェックされない場合があります。
開発
npm run build
npm test
ライセンス
MIT — GuardBee
フィードバック
質問、アイデア、誤検出などがあれば、GitHub Discussions でスレッドを立てるか、issue を作成してください。GuardBee が役に立った場合は、リポジトリに ⭐ を付けていただけると、ほかの人にも見つけてもらいやすくなります。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。