关于 unbounded-consumption-auditor
面向开发者的 MCP 服务及命令行工具,用于审查 LLM 和 Agent 应用代码中可能导致费用失控的无界消耗风险。它通过有限范围的启发式规则检查令牌上限、超时、循环、被禁用的框架限制和速率限制。
主要功能
- 01查找缺失的令牌上限和超时
- 02检测无界 Agent 与重试循环
- 03标记被禁用的框架安全限制
- 04检查计费型 MCP 调用是否限流
- 05导出 SARIF 2.1.0 结果
适用场景
- 01扫描 LLM 应用代码中的成本风险
- 02检查 Agent 循环和重试处理
- 03将静态检查加入 CI/CD
MCP 相关
提供扫描代码片段、文件和目录以及列出检测模式的工具。MCP 客户端可用它审查 LLM 和 Agent 源码。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
4收录的工具列表 · 更新于 2 周前
| 参数 | 类型 | 必填 | 说明 |
|---|---|---|---|
| label | string | 否 | 在发现结果中显示的可选标签(例如文件名) |
| content | string | 是 | 要扫描的代码内容 |
详细介绍
@guardbee/mcp-unbounded-consumption-auditor
🇬🇧 English | 🇹🇷 Türkçe | 🇨🇳 中文 | 🇯🇵 日本語 | 🇰🇷 한국어 | 🇧🇷 Português | 🇪🇸 Español | 🇩🇪 Deutsch
一个 MCP(模型上下文协议)服务,用于扫描 LLM/Agent 应用代码中的无限制消耗——这是 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 对这一类别的说明中给出了一个具体的成本示例,阅读审计结果时值得牢记:“一个没有递归限制或调用预算的研究助手 Agent 最终进行了 500 次工具调用,模拟成本为 10 美元……而一个设有调用预算、递归深度限制和 Agent 熔断器的 Agent……只完成了一次工具调用,仅花费 0.02 美元。”
为什么特别选择这五项检查
这里的每个模式在编写前都对照真实的 SDK 源码或真实代码进行了验证,而不是根据训练数据中的假设猜测。
- 缺少令牌限制针对未设置
max_tokens或max_completion_tokens的.chat.completions.create(...)调用(OpenAI Python/JS)。它刻意仅适用于 OpenAI 风格的调用:Anthropic 自己的 SDK 将max_tokens设为必需的构造参数——甚至在请求发送之前就会报错——因此如果也在那里匹配,100% 都是误报。推理模型(o1+)会静默忽略max_tokens,而需要改用max_completion_tokens,所以此检查只会标记这两个参数都缺失的调用。 - 缺少超时针对手动编写的
requests/axios/fetch调用,要求其自身的参数范围中提及已知的大模型端点(api.openai.com、api.anthropic.com、/chat/completions、/v1/messages)。官方 OpenAI/Anthropic SDK 已提供有界的客户端级默认值(openai-node:600s),标记这些调用只会带来干扰。requests.post()自己的 Quickstart 警告称,未设置timeout可能导致程序无限期等待;axios 和裸fetch也存在相同的无默认超时情况。 - 无界循环涵盖两种真实代码中经验证的模式:一种是手动编写的
while True:/while(true)Agent 循环,会分发tool_calls,但附近没有任何迹象表明设置了迭代次数上限(具体模式取自一个公开的 70 行 Agent 演练教程);另一种是重试循环,它会捕获异常、直接再次调用大模型,然后在没有尝试次数计数器的情况下执行continue(OWASP 自己的说明明确指出了这一点:“a failed step might be retried repeatedly”)。重试循环检查刻意限定为实际调用大模型的循环——在一次真实开源代码库测试中,早期未做此限制的版本误标了普通的轮询/重试代码(见下文“开发”)。 - 已禁用安全限制会标记
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没有等效用法——它要求提供一个具体数字——因此这里没有为它发布模式,而不是去猜测一种未经验证的“禁用”机制。 - 缺少速率限制是这里唯一的启发式模式,特意以中等(而非高/严重)严重级别发布:与 LangChain/LangGraph 为迭代次数上限提供的有界默认值不同,MCP SDK(TypeScript 或 Python)都没有在工具注册时提供内置的按调用方限流钩子。多篇相互独立的 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 引用(真实的 Agent 调度模式),并会明确跳过附近可见上限提示的循环。
功能
- 7 种模式,涵盖 5 个类别;每种模式都基于真实 SDK 源代码、真实代码讲解或 OWASP 自己的 2026 年文章,并在模式注释中内联引用
- 25 项测试(每种模式都有正向和负向测试,包括构建无界循环检查所依据的、逐字引用的真实循环代码片段)
- SARIF 2.1.0 输出 — CI/CD 集成(GitHub Code Scanning 等)
- 端到端验证:使用植入漏洞的测试样例(捕获了全部 7 种模式,并正确跳过了全部 3 种“安全对应项”负向情况),以及一个包含 3,414 个文件的真实开源代码库(
IBM/mcp-context-forge)和本单体代码库自身的 495 个文件 — 生产代码中零误报。发版前的验证过程中确实发现并修复了两个真实误报:较早版本的循环体窗口范围较宽,导致同一文件中其他位置的无关except/continue被误认为属于附近的循环(通过要求窗口中包含 LLM 调用提示并缩小窗口范围修复);循环下方几行中被禁用的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 | 缺少令牌上限 | 中 | OpenAI 聊天补全调用既未设置 max_tokens,也未设置 max_completion_tokens |
raw_http_call_to_llm_endpoint_missing_timeout | 缺少超时 | 中 | 对已知大模型端点进行的手写 HTTP 调用没有设置超时/AbortSignal |
unbounded_tool_calling_loop | 无界循环 | 中 | 手写的 while(true)/while True: 循环会分发 tool_calls,但没有可见的迭代上限 |
unbounded_retry_loop | 无界循环 | 中 | 大模型调用周围的重试循环会捕获异常并继续,但没有尝试次数计数器 |
langchain_max_iterations_disabled | 安全限制已禁用 | 高 | LangChain 的 AgentExecutor 将 max_iterations 显式设为 None |
openai_agents_max_turns_disabled | 安全限制已禁用 | 高 | openai-agents-python 的 Runner 将 max_turns 显式设为 None |
mcp_tool_billable_call_no_rate_limit | 缺少速率限制 | 中 | MCP 工具处理程序执行了计费的大模型调用,但没有任何迹象表明存在按调用者进行的速率限制 |
配置(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 中发起讨论,或提交问题。如果 GuardBee 对你有帮助,请在代码仓库点一个 ⭐,帮助其他人发现它。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。