Unbounded Consumption Auditor

io.github.4hmetuyar由 GitHub 账号 4hmetuyar 发布v0.1.2更新于 Oct 24, 2026

Scans LLM/agent code for Unbounded Consumption / denial-of-wallet risks (OWASP LLM Top 10 2026 #6)

已验证STDIO仅桌面开发者工具安全与监控

概览

AI 生成的概览

扫描 LLM 与智能体源代码中的无界消耗(denial of wallet)风险,例如缺少 token 上限、超时、循环上限和速率限制。

可以做什么
这是一个本地 MCP 服务器,用于审计 LLM 与智能体应用代码中的无界消耗模式(OWASP LLM Top 10 2026 第 6 类)。它提供扫描代码片段、单个文件、递归扫描目录以及列出检测模式的工具。它报告五大类共七种模式,包括缺少 token 上限、手写 LLM HTTP 调用缺少超时、无界智能体或重试循环、被禁用的框架安全上限,以及 MCP 工具处理程序在没有可见速率限制的情况下发起计费调用。输出可生成 SARIF 2.1.0 以便集成 CI/CD。
适用场景
适合在审查或维护 LLM 与智能体代码时,快速检查成本失控风险。也适合在 CI 流程中让高危发现导致构建失败,或在交互式场景中由助手扫描片段或目录并解释结果。
运行要求
作为本地 stdio 进程运行,通常通过 npx 从 npm 包 @guardbee/mcp-unbounded-consumption-auditor 启动。需要 Node.js 以及用于安装软件包的网络访问。未声明任何账户、API 密钥或请求头。
安装前请注意
该软件包默认发送使用遥测,据说明为工具名称加简短参数,不包含被扫描的代码;可通过环境变量 GUARDBEE_TELEMETRY=0 关闭。检测结果为启发式,并非完整控制流分析,因此循环体过长、在别处实施速率限制或集中配置默认值的情况可能被漏报或逐个标记。

安装

在 SourceWeft 中

  1. 打开 控制台中的 Unbounded Consumption Auditor,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

README

@guardbee/mcp-unbounded-consumption-auditor

🇬🇧 English | 🇹🇷 Türkçe | 🇨🇳 中文 | 🇯🇵 日本語 | 🇰🇷 한국어 | 🇧🇷 Português | 🇪🇸 Español | 🇩🇪 Deutsch

[npm version] [npm downloads] [License: MIT]

An MCP (Model Context Protocol) server that scans LLM/agent application code for Unbounded Consumption — OWASP LLM Top 10 2026's #6 category, also known as "denial of wallet": nothing stops the application from making unlimited billable calls.

Telemetry is off by default. With GUARDBEE_TELEMETRY=1 it sends the server, tool, success, duration and short parameter values such as a file path; longer strings and fields like content, token or password are replaced with a placeholder. See @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's own write-up on this category gives a concrete cost example worth keeping in mind while reading findings: "A research assistant agent without any recursion limit or call budget ended up making 500 tool calls with a simulated cost of $10... An agent with a call budget, a recursion depth limit and an agentic circuit breaker... completed one tool call, spending just $0.02."


Why these five checks specifically

Every pattern here was checked against real SDK source or real code before being written — not guessed from training-data assumption.

  • Missing token limit targets .chat.completions.create(...) calls (OpenAI Python/JS) with neither max_tokens nor max_completion_tokens set. It's deliberately scoped to OpenAI-shaped calls only: Anthropic's own SDK makes max_tokens a required constructor argument — it raises before the request is even sent — so a matching check there would be 100% false positives. Reasoning models (o1+) silently ignore max_tokens and need max_completion_tokens instead, so the check only flags a call missing both.
  • Missing timeout targets hand-rolled requests/axios/fetch calls whose own argument span mentions a known LLM endpoint (api.openai.com, api.anthropic.com, /chat/completions, /v1/messages). The official OpenAI/Anthropic SDKs already ship a bounded client-level default (openai-node: 600s) — flagging those would just be noise. requests.post()'s own Quickstart warns that an unset timeout can leave a program waiting indefinitely; axios and bare fetch have the same no-default-timeout shape.
  • Unbounded loop covers two real shapes, both real-code-verified: a hand-rolled while True:/while(true) agent loop that dispatches tool_calls with nothing nearby suggesting an iteration cap (the exact shape quoted from a public 70-line-agent walkthrough), and a retry loop that catches an exception, calls straight back into an LLM, and continues with no attempt counter (OWASP's own write-up calls this out by name: "a failed step might be retried repeatedly"). The retry-loop check is deliberately scoped to loops that actually call an LLM — an early version without that scoping flagged ordinary polling/retry code in a real open-source codebase during testing (see Development below).
  • Disabled safety limit flags max_iterations=None (LangChain's AgentExecutor) and max_turns=None (openai-agents-python's Runner.run/run_sync) — both verified against real source before shipping. LangChain's AgentExecutor defaults max_iterations to 15, and its own _should_continue() only enforces the cap if self.max_iterations is not None — so None genuinely disables it. openai-agents-python's own issue tracker states plainly that max_turns=None disables the turn limit. LangGraph's recursion_limit has no equivalent — it requires a concrete number — so no pattern is shipped for it, rather than guessing at an unverified "disable" mechanism.
  • Missing rate limit is the one heuristic pattern here, shipped at medium (not high/critical) severity on purpose: no MCP SDK (TypeScript or Python) provides a built-in per-caller throttling hook on tool registration, unlike the bounded defaults LangChain/LangGraph ship for iteration caps. Multiple independent 2026 write-ups describe the fix as a hand-rolled wrapper around server.tool()/@mcp.tool(), implying there's no framework default to fall back on. This check can't see a rate limiter enforced elsewhere (an API gateway, middleware in another file) — see Limitations.

Relationship to ai-code-scanner: that package already has a coarser unbounded_agent_loop pattern (any while(true)/for(;;) within 200 characters of a .chat.completions.create/.messages.create call, under its excessive-agency category) — it doesn't check whether the loop actually dispatches tool calls, and doesn't check for a nearby iteration-cap hint, so it would also flag a loop that's already properly bounded. This package's unbounded_tool_calling_loop is narrower and cost-specific: it requires an actual tool_calls/toolCalls reference (the real agentic-dispatch shape) and explicitly skips loops with a visible cap hint nearby.


Features

  • 7 patterns across 5 categories, each grounded in real SDK source, a real code walkthrough, or OWASP's own 2026 write-up — cited inline in the pattern comments
  • 25 tests (positive + negative for every pattern, including the exact quoted real-world loop snippet the unbounded-loop checks are built from)
  • SARIF 2.1.0 output — CI/CD integration (GitHub Code Scanning, etc.)
  • End-to-end verified against a planted-vulnerability fixture (all 7 patterns caught, all 3 "safe counterpart" negatives correctly skipped) and against a real 3,414-file open-source codebase (IBM/mcp-context-forge) plus this monorepo's own 495 files — zero false positives in production code. Two real false positives were found and fixed during that verification, before shipping: an early, wider loop-body window let an unrelated except/continue elsewhere in the same file get mistaken for part of a nearby loop (fixed by requiring an LLM-call hint in the window and shrinking it), and a disabled max_iterations=None a few lines below a loop was briefly mistaken for a legitimate nearby iteration cap (fixed by stripping disabled-cap assignments before testing for a real one).

Quick Start

Claude Desktop / MCP Client

json
{  "mcpServers": {    "guardbee-unbounded-consumption-auditor": {      "command": "npx",      "args": ["-y", "@guardbee/mcp-unbounded-consumption-auditor"]    }  }}

CLI (CI/CD)

bash
npx @guardbee/mcp-unbounded-consumption-auditor scan . --fail-on=high --format=sarif > results.sarif

MCP Tools

ToolDescription
scan_textScan a code snippet for Unbounded Consumption anti-patterns
scan_fileScan a single file
scan_directoryRecursively scan a directory
list_patternsList every pattern this auditor detects, grouped by category

Detected Patterns

PatternCategorySeverityMeaning
openai_chat_completion_missing_max_tokensmissing-token-limitmediumAn OpenAI chat completion call has neither max_tokens nor max_completion_tokens set
raw_http_call_to_llm_endpoint_missing_timeoutmissing-timeoutmediumA hand-rolled HTTP call to a known LLM endpoint has no timeout/AbortSignal
unbounded_tool_calling_loopunbounded-loopmediumA hand-rolled while(true)/while True: loop dispatches tool_calls with no visible iteration cap
unbounded_retry_loopunbounded-loopmediumA retry loop around an LLM call catches an exception and continues with no attempt counter
langchain_max_iterations_disableddisabled-safety-limithighLangChain's AgentExecutor max_iterations explicitly set to None
openai_agents_max_turns_disableddisabled-safety-limithighopenai-agents-python's Runner max_turns explicitly set to None
mcp_tool_billable_call_no_rate_limitmissing-rate-limitmediumAn MCP tool handler makes a billable LLM call with nothing suggesting per-caller rate limiting

Configuration (guardbee.yml)

yaml
unbounded-consumption-auditor:  fail-on: high         # any | critical | high | medium | low | none  max-files: 5000  exclude:    - ".test.ts"

Limitations (by design)

  • Bounded-window heuristics, not real control-flow analysis. The loop checks look at a fixed character window after while True:/while(true), not the actual loop body — a loop with an unusually long body, or one whose cap check lives outside that window, can be missed. Testing against real code found the reverse failure mode too (an unrelated except/continue further down getting mistaken for part of a nearby loop) and tightened the window accordingly; it's still a heuristic, not a parser.
  • The rate-limit check can't see enforcement elsewhere. A tool handler with no rate-limiter in its own body might still be protected by an API gateway, middleware in another file, or a wrapper this scanner doesn't trace into — this check flags what's visible in the handler itself, nothing more.
  • No cross-function default detection. If a project sets an output limit or timeout once, centrally, and every call site relies on that default implicitly (rather than passing it per-call), the per-call checks here will still flag each call site individually.
  • LangGraph's recursion_limit isn't checked. Unlike LangChain and openai-agents-python, LangGraph's recursion limit requires a concrete number — there's no verified "set it to disable" mechanism, so no pattern is shipped for it rather than guessing at one.

Development

bash
npm run buildnpm test             # 25 unit tests

License

MIT — GuardBee

Feedback

Questions, ideas, or a false positive? Start a thread in GitHub Discussions or open an issue. If GuardBee is useful to you, a ⭐ on the repository helps others find it.

来源:packages/unbounded-consumption-auditor/README.md,提交 040e072

工具

0
SourceWeft 尚未在沙箱中启动过该软件包,因此其工具未知。

版本历史

1
  1. v0.1.2最新Sep 29, 2026

评分

已满足适用检查项的 50%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分

    请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。

  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具15 分

    请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。

  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分