unbounded-consumption-auditor について
開発者向けの MCP サーバー兼 CLI で、LLMやエージェントのアプリケーションコードにある、過剰なコストにつながる無制限消費のリスクを監査します。トークン上限、タイムアウト、ループ、無効化されたフレームワーク制限、レート制限を範囲を限定したヒューリスティックで検査します。
主な機能
- 01トークン上限とタイムアウトの欠落を検出
- 02無制限のエージェント・再試行ループを検出
- 03無効化されたフレームワーク制限を警告
- 04課金対象のMCP呼び出しのレート制限を確認
- 05SARIF 2.1.0形式で結果を出力
活用シーン
- 01LLMアプリのコストリスクをスキャン
- 02エージェントのループと再試行処理を確認
- 03CI/CDに静的チェックを追加
MCP 対応
コード断片、ファイル、ディレクトリのスキャンと、検出パターンの一覧表示を行うツールを提供します。MCPクライアントからLLMやエージェントのソースコード監査に利用できます。
設定
ローカルサーバーの設定はどのクライアントでも共通です。コピーしてクライアントの MCP 設定ファイルに貼り付けてください。
ツール
4掲載時のツール一覧 · 2 週間前に更新
| パラメーター | 型 | 必須 | 説明 |
|---|---|---|---|
| label | string | いいえ | 検出結果に表示する任意のラベル(例:ファイル名) |
| content | string | はい | スキャンするコードの内容 |
詳細
@guardbee/mcp-unbounded-consumption-auditor
🇬🇧 English | 🇹🇷 Türkçe | 🇨🇳 中文 | 🇯🇵 日本語 | 🇰🇷 한국어 | 🇧🇷 Português | 🇪🇸 Español | 🇩🇪 Deutsch
LLM/エージェントのアプリケーションコードをスキャンし、無制限の消費を検出する MCP(Model Context Protocol)サーバーです。これは OWASP LLM Top 10 2026 の第6カテゴリーで、「ウォレット拒否」とも呼ばれます。アプリケーションが課金対象の呼び出しを無制限に実行できてしまう状態を指します。
テレメトリーはデフォルトでオフです。
GUARDBEE_TELEMETRY=1を設定すると、サーバー、ツール、成功の有無、所要時間、およびファイルパスなどの短いパラメーター値を送信します。長い文字列やcontent、token、passwordなどのフィールドはプレースホルダーに置き換えられます。詳細は@guardbee/mcp-telemetryをご覧ください。
Claude ──► unbounded-consumption-auditor ──► your LLM/agent source
│
├─ missing-token-limit (no cap on how much the model can generate)
├─ missing-timeout (a hand-rolled call to an LLM endpoint that can hang forever)
├─ unbounded-loop (an agent/retry loop with no iteration cap)
├─ disabled-safety-limit (a framework's own loop cap explicitly turned off)
└─ missing-rate-limit (an MCP tool making billable calls with no throttling)
このカテゴリーに関する OWASP 独自の解説には、検出結果を読む際に参考になる具体的なコスト例が記載されています。「再帰の上限も呼び出し予算も設定されていないリサーチアシスタントエージェントが、シミュレーション上で10ドル相当のコストを伴うツール呼び出しを500回実行しました……呼び出し予算、再帰深度の上限、エージェント型サーキットブレーカーを備えたエージェントは……ツールを1回呼び出すだけで処理を完了し、支出はわずか0.02ドルでした。」
なぜ特にこの5つのチェックなのか
ここにあるすべてのパターンは、トレーニングデータ上の想定で推測したものではなく、実際の SDK ソースまたは実際のコードと照合してから記述しています。
- トークン上限の未設定は、
max_tokensもmax_completion_tokensも設定されていない.chat.completions.create(...)の呼び出し(OpenAI Python/JS)を対象にします。意図的に OpenAI 形式の呼び出しだけに絞っています。Anthropic 独自の SDK ではmax_tokensが必須のコンストラクター引数であり、リクエストが送信される前にエラーになるため、そこでも同じチェックを行うと誤検知率が100%になります。推論モデル(o1以降)はmax_tokensを黙って無視し、代わりにmax_completion_tokensが必要になるため、このチェックでは両方が欠けている呼び出しのみを検出します。 - タイムアウトの未設定は、既知の LLM エンドポイント(
api.openai.com、api.anthropic.com、/chat/completions、/v1/messages)への言及が引数の範囲内にある、手書きのrequests/axios/fetchの呼び出しを対象にします。OpenAI/Anthropic の公式 SDK には、クライアントレベルで上限のあるデフォルト値(openai-node は600秒)がすでに設定されています。これらを検出しても、ノイズになるだけです。requests.post()のクイックスタートでは、timeoutを設定しないとプログラムが無期限に待機する可能性があると警告しています。axios と素のfetchも、デフォルトのタイムアウトがないという点で同じです。 - 上限のないループは、実際のコードで確認した2つの形を対象にします。どちらも実際のコードで検証済みです。1つ目は、反復回数の上限を示すものが近くにない、
tool_callsをディスパッチする手書きのwhile True:/while(true)エージェントループです(公開されている70行のエージェント解説から正確な形を引用しています)。2つ目は、例外を捕捉して LLM を直接再度呼び出し、試行回数のカウンターなしでcontinueする再試行ループです(OWASP の解説でも、「失敗したステップが繰り返し再試行される可能性がある」と明示されています)。再試行ループのチェックは、LLM を実際に呼び出すループに意図的に限定しています。この条件を付ける前の初期バージョンは、テスト中に実際のオープンソースコードベースで一般的なポーリング/再試行コードまで検出していました(詳しくは「開発」を参照)。 - 安全上限の無効化は、
max_iterations=None(LangChain のAgentExecutor)とmax_turns=None(openai-agents-python のRunner.run/run_sync)を検出します。どちらもリリース前に実際のソースで確認済みです。LangChain のAgentExecutorではmax_iterationsのデフォルト値が15で、独自の_should_continue()はself.max_iterations is not Noneの場合にのみ上限を適用します。そのため、Noneにすると実際に上限が無効になります。openai-agents-python 自身の課題トラッカーには、max_turns=Noneでターン数の上限が無効になると明記されています。LangGraph のrecursion_limitには同等の設定がなく、具体的な数値が必須です。そのため、未検証の「無効化」方法を推測してパターンを追加することはしていません。 - レート制限の未設定は、ここにある中で唯一のヒューリスティックなパターンです。意図的に深刻度を「中」(「高」や「重大」ではなく)に設定しています。TypeScript または Python の MCP SDK には、LangChain/LangGraph が反復回数の上限に対して提供しているような、ツール登録時に呼び出し元ごとのスロットリングを行う組み込みフックがないためです。2026年の複数の独立した解説では、
server.tool()/@mcp.tool()を手書きのラッパーで囲む方法が修正策として説明されており、フレームワークのデフォルト設定に頼れないことが示されています。このチェックでは、別の場所で適用されているレートリミッター(API ゲートウェイや別ファイルのミドルウェアなど)は検出できません。詳しくは「制限事項」を参照してください。
**ai-code-scanner との関係:**このパッケージには、より大まかな unbounded_agent_loop パターンがすでにあります。これは excessive-agency カテゴリーで、.chat.completions.create/.messages.create の呼び出しから200文字以内にある、あらゆる while(true)/for(;;) を検出します。ただし、ループが実際にツール呼び出しをディスパッチしているかは確認せず、近くに反復回数の上限を示すものがあるかも確認しないため、すでに適切に上限が設定されたループも検出してしまいます。このパッケージの unbounded_tool_calling_loop は、より限定的でコストに特化しています。実際のエージェント型ディスパッチの形である tool_calls/toolCalls の参照が必須で、近くに上限の明示があるループは検出対象から除外します。
特徴
- 5 つのカテゴリにわたる 7 つのパターン。それぞれの根拠は、実際の SDK ソース、実際のコードの解説、または OWASP 独自の 2026 年の解説であり、パターンのコメント内に引用を記載しています
- 25 件のテスト(すべてのパターンに対する肯定・否定の両方のテストを含みます。また、無制限ループのチェックの基になった、実際のループスニペットをそのまま引用したテストも含みます)
- SARIF 2.1.0 出力 — CI/CD との統合(GitHub Code Scanning など)
- 脆弱性を仕込んだフィクスチャ(7 つのパターンすべてを検出し、「安全な対照例」の否定ケース 3 件をすべて正しくスキップ)と、3,414 ファイルからなる実際のオープンソースコードベース(
IBM/mcp-context-forge)、およびこのモノレポ自体の 495 ファイルを対象に、エンドツーエンドで検証済みです。実運用コードでの誤検出はゼロです。この検証中、リリース前に実際の誤検出が 2 件見つかり、修正されました。1 件目は、初期の広すぎるループ本体の探索範囲により、同じファイル内の別の場所にある無関係なexcept/continueが近くのループの一部と誤認された問題です(探索範囲内に LLM 呼び出しのヒントがあることを必須にし、探索範囲を縮小して修正)。2 件目は、ループの数行下にある無効化されたmax_iterations=Noneが、近くにある有効な反復上限と一時的に誤認された問題です(有効な上限の有無を確認する前に、無効化された上限設定を除去して修正)。
クイックスタート
Claude Desktop / MCP クライアント
{
"mcpServers": {
"guardbee-unbounded-consumption-auditor": {
"command": "npx",
"args": ["-y", "@guardbee/mcp-unbounded-consumption-auditor"]
}
}
}
CLI(CI/CD)
npx @guardbee/mcp-unbounded-consumption-auditor scan . --fail-on=high --format=sarif > results.sarif
MCP ツール
| ツール | 説明 |
|---|---|
scan_text | コードスニペットをスキャンし、無制限の消費に関するアンチパターンを検出します |
scan_file | 単一のファイルをスキャンします |
scan_directory | ディレクトリを再帰的にスキャンします |
list_patterns | この監査ツールが検出するすべてのパターンをカテゴリ別に一覧表示します |
検出されるパターン
| パターン | カテゴリ | 重大度 | 説明 |
|---|---|---|---|
openai_chat_completion_missing_max_tokens | missing-token-limit | medium | OpenAI のチャット補完呼び出しで、max_tokens も max_completion_tokens も設定されていません |
raw_http_call_to_llm_endpoint_missing_timeout | missing-timeout | medium | 既知の LLM エンドポイントへの手書きの HTTP 呼び出しに、タイムアウト/AbortSignal がありません |
unbounded_tool_calling_loop | unbounded-loop | medium | 手書きの while(true)/while True: ループが、目に見える反復上限なしで tool_calls をディスパッチしています |
unbounded_retry_loop | unbounded-loop | medium | LLM 呼び出しを囲む再試行ループが、試行回数カウンターなしで例外を捕捉して処理を続行しています |
langchain_max_iterations_disabled | disabled-safety-limit | high | LangChain の AgentExecutor で max_iterations が明示的に None に設定されています |
openai_agents_max_turns_disabled | disabled-safety-limit | high | openai-agents-python の Runner で max_turns が明示的に None に設定されています |
mcp_tool_billable_call_no_rate_limit | missing-rate-limit | medium | MCP ツールハンドラーが、呼び出し元ごとのレート制限を示すものがない状態で、課金対象の LLM 呼び出しを行っています |
設定(guardbee.yml)
unbounded-consumption-auditor:
fail-on: high # any | critical | high | medium | low | none
max-files: 5000
exclude:
- ".test.ts"
制限事項(設計上のもの)
- 実際の制御フロー解析ではなく、範囲を限定したヒューリスティックです。 ループのチェックでは、実際のループ本体ではなく、
while True:/while(true)の後の固定文字数の範囲を調べます。そのため、本体が極端に長いループや、上限チェックがその範囲外にあるループは見逃す可能性があります。実際のコードでテストしたところ、逆の誤検出も見つかりました(さらに下にある無関係なexcept/continueを近くのループの一部と誤認するケースです)。それを受けて範囲を調整しましたが、依然としてヒューリスティックであり、パーサーではありません。 - レート制限チェックでは、別の場所での適用状況を確認できません。 ツールハンドラー本体にレートリミッターがなくても、API ゲートウェイ、別ファイルのミドルウェア、またはこのスキャナーが追跡しないラッパーによって保護されている可能性があります。このチェックが検出するのは、ハンドラー自体で確認できる内容のみです。
- 関数をまたいだデフォルト値の検出には対応していません。 プロジェクトで出力上限やタイムアウトを一度だけ中央で設定し、各呼び出し箇所がそのデフォルト値を暗黙的に使用している場合(呼び出しごとに渡すのではなく)、ここでの呼び出しごとのチェックでは、各呼び出し箇所に個別に警告が出ます。
- LangGraph の
recursion_limitはチェックしません。 LangChain や openai-agents-python とは異なり、LangGraph の再帰制限には具体的な数値が必要です。無効化するための検証済みの設定方法がないため、推測でパターンを追加するのではなく、パターンを用意していません。
開発
npm run build
npm test # 25 unit tests
ライセンス
MIT — GuardBee
フィードバック
質問、アイデア、または誤検出がありましたら、GitHub Discussions でスレッドを立てるか、issue を作成してください。GuardBee が役に立った場合は、リポジトリに ⭐ を付けていただけると、ほかの人にも見つけてもらいやすくなります。
コメント
AI アプリケーションが外部のツールやデータソースに統一的な方法で接続するためのオープンなプロトコルです。クライアントはモデルとの対話を担い、MCP サーバーはツール・リソース・プロンプトテンプレートを提供します。標準メッセージでやり取りするため、1 つのサーバーを複数のクライアントで再利用できます。