关于 shimguard
ShimGuard 检查标记为已修复的 GitHub issue 所引用的 PR 是否确已合并,也可检查指定漏洞代码模式是否仍存在于 HEAD。它面向维护者和安全团队,可用于验证追踪器声明及 CI 检查。
主要功能
- 01检查所引 PR 的合并状态
- 02可选检查 HEAD 中的代码模式
- 03返回 MATCH、MISMATCH 和 UNVERIFIED
- 04为脚本和 Agent 提供 JSON 输出
- 05适用于 CI 的退出码
适用场景
- 01核查已关闭安全 issue 的修复状态
- 02在 CI 中拦截引用未合并修复的 issue
- 03检查所引漏洞模式是否仍然存在
MCP 相关
MCP 服务提供一个 run 工具,接收 shimguard CLI 参数并返回结构化结果;如有 JSON 输出,也会解析后提供。
配置
本地服务的配置在各客户端中通用,复制后粘贴到客户端的 MCP 配置文件即可。
工具
本地服务需要在你的电脑上运行后才能读取工具,维护者暂未提供工具列表。
详细介绍
ShimGuard
在信任问题跟踪器之前,验证标记为“已修复”并关闭的 GitHub 问题是否确实有已合并的修复。

npx shimguard-cli verify sybil-solutions/codex-shim --issues 38,41,42,43,45,46
对真实的 sybil-solutions/codex-shim 仓库(超过 1,000 个 Star)运行这条命令,结果发现 6 个 MISMATCH:6 个安全问题都附有“已在 PR #52 中修复”的评论并被关闭,但 PR #52 实际上从未合并。漏洞代码至今仍在 main 中。阅读已关闭问题的人无从得知这一点。
目录
为何需要它
阅读问题跟踪器时,你会相信两个信号:问题的 state(打开或关闭),以及维护者的关闭评论(“已在 #N 中修复”)。GitHub 本身不会根据实际情况验证这两个信号。维护者可能会引用一个从未合并的 PR 来关闭问题;自动化机器人可能会在 PR 真正合并之前,根据 PR 描述中的“fixes #N”关键词关闭问题;或者修复可能会在问题关闭后被撤销。这些情况都会导致跟踪器将仍然存在的 Bug 标记为“已修复”。
ShimGuard 会检查人工浏览问题时容易忽略的一点:跟踪器引用的修复 PR 是否真的显示 merged: true?这是一个简单、机械且明确的检查,而非启发式判断或猜测。
安装
ShimGuard 提供两个独立且同等重要的一流软件包——选择适合你工具链的那个,或同时安装两者。两者互不取代,也没有任何一个已弃用;它们都会通过同一个 GitHub REST API 执行相同的检查:“已关闭的问题引用了 Fixed in PR #N,而 #N 是否确实已合并?”
# npm -- JavaScript/TypeScript CLI + library
npm install -g shimguard-cli
# or run it once with no install
npx shimguard-cli verify <owner>/<repo> --issues <numbers>
# PyPI -- Python CLI + library (genuine port, not a wrapper around the Node binary)
pip install shimguard-cli
npm CLI 需要 Node.js 18 或更高版本(使用内置的 fetch API)。Python 软件包的 CLI 入口点也名为 shimguard(例如 shimguard verify sybil-solutions/codex-shim --issues 45,46);Python 专属的使用指南请参阅 python/README.md 和 docs/getting-started.md,各发行版本的版本历史请参阅 CHANGELOG.md。
快速开始
shimguard verify sybil-solutions/codex-shim --issues 38,41,42,43,45,46
ShimGuard v0.1 -- Tracker Verification: sybil-solutions/codex-shim
[MISMATCH] Issue #45 "_resolve_api_key silently falls back to Cursor API key for any model with an empty api_key, forwarding it to arbitrary upstream URLs"
https://github.com/sybil-solutions/codex-shim/issues/45
Cited fix: PR #52 (open, not merged)
Issue is closed and cites PR #52 as the fix, but that PR is open and was never merged.
Summary: 6 MISMATCH, 0 MATCH, 0 UNVERIFIED (6 checked)
发现任何 MISMATCH 时,退出代码为 1(适用于设置 CI 门禁);所有已检查问题所声称的修复都确实已合并时,退出代码为 0;发生用法或网络错误时,退出代码为 2。
ShimGuard 不只是用来发现意外情况:对一组问题运行它时,它能正确并列报告 MATCH、UNVERIFIED 和 MISMATCH;只要没有可证实的问题,就会以 0 退出——这正是 CI 门禁需要的信号。

可选:验证代码本身,而不只是合并状态
如需更严格的检查,可让 ShimGuard 检查特定文件和问题中标记为易受攻击代码的模式:
cat > patterns.json <<'EOF'
{
"45": { "path": "codex_shim/settings.py", "pattern": "cursor_key_fallback" }
}
EOF
shimguard verify sybil-solutions/codex-shim --issues 45 --patterns patterns.json
如果 PR 已合并,但引用的模式仍存在于 HEAD 中的文件里,ShimGuard 仍会报告 MISMATCH:PR 已合并并不保证特定的易受攻击代码行已被移除。
警告
pattern会编译为 JavaScriptRegExp,而path会经过验证,确保其位于目标仓库内(不能通过..遍历到其他仓库或 API 端点)。--patterns只能指向你自己编写或审查过的文件。请参阅 SECURITY.md。
CLI 参考
Usage: shimguard [options] [command]
Verify that GitHub issues closed as "fixed" actually have a merged fix. Catches
security issues marked fixed whose PR was never merged.
Options:
-V, --version output the version number
-h, --help display help for command
Commands:
verify [options] <repo> Check whether closed issues in a repo actually have
a merged fix
help [command] display help for command
Usage: shimguard verify [options] <repo>
Check whether closed issues in a repo actually have a merged fix
Arguments:
repo target repo as <owner>/<repo>, e.g.
sybil-solutions/codex-shim
Options:
--issues <numbers> comma-separated issue numbers to check, e.g. 38,41,42
--patterns <file> JSON file mapping issue number -> {path, pattern} for an
optional code-pattern check
--token <token> GitHub token for higher API rate limits (defaults to
$GITHUB_TOKEN)
--format <format> output format: text or json (default: "text")
-h, --help display help for command
--format json 的输出格式稳定,专为脚本和 AI Agent 直接解析而设计:
{
"repo": "sybil-solutions/codex-shim",
"checked": 1,
"summary": { "mismatch": 1, "match": 0, "unverified": 0 },
"results": [
{
"issue": { "number": 45, "title": "...", "state": "closed", "htmlUrl": "..." },
"citedPullRequest": { "number": 52, "state": "open", "merged": false, "htmlUrl": "..." },
"patternCheck": null,
"verdict": "MISMATCH",
"reason": "Issue is closed and cites PR #52 as the fix, but that PR is open and was never merged."
}
]
}

MCP 服务
ShimGuard 随附一个模型上下文协议服务,因此兼容 MCP 的 Agent(Claude Desktop、Claude Code、Cursor 或任何其他 MCP 客户端)可以将其作为工具调用,而不必通过命令行调用 CLI 并解析文本。它包含在 Python 发行包中:
pip install "shimguard-cli[mcp]"
将其注册到 Claude Desktop 等 MCP 客户端:
{
"mcpServers": {
"shimguard": {
"command": "shimguard-mcp"
}
}
}
它提供单个工具 run,接受你传给 shimguard CLI 的完整 argv,并返回结构化结果(成功时为 {returncode, stdout, stderr, json?};如果命令失败、超时或以非零状态码退出,则为 {error: ...})。调用示例:
run(args=["verify", "sybil-solutions/codex-shim", "--issues", "45,46", "--format", "json"])
它会返回与上文所示相同的 --format json 报告,其中解析后的内容位于 json 字段,原始输出则位于 stdout。完整详情请见 Python 包 README。
库 API
也可以直接导入 ShimGuard 的验证逻辑:
import { TrackerVerifier, RestGitHubClient, RegexPatternMatcher } from "shimguard-cli";
const client = new RestGitHubClient(process.env.GITHUB_TOKEN);
const verifier = new TrackerVerifier(client, new RegexPatternMatcher(client));
const result = await verifier.verify({ owner: "sybil-solutions", repo: "codex-shim", number: 45 });
console.log(result.verdict); // "MISMATCH"
TrackerVerifier 接受任意 GitHubClient 和一个可选的 PatternMatcher(请参阅 src/types.ts、src/pattern-matcher.ts)。二者都是接口,因此未来本地配置扫描器或其他代码托管平台可以接入,而无需更改验证器本身。
Python 包提供相同形式的接口:
from shimguard import TrackerVerifier, RestGitHubClient, RegexPatternMatcher, IssueRef
client = RestGitHubClient() # or RestGitHubClient(token=os.environ["GITHUB_TOKEN"])
verifier = TrackerVerifier(client, RegexPatternMatcher(client))
result = verifier.verify(IssueRef(owner="sybil-solutions", repo="codex-shim", number=45))
print(result.verdict) # "MISMATCH"
横向对比
在撰写本文前,我们搜索了问题修复验证工具、补丁验证工具和安全公告修复工具,未发现任何现有开源工具会检查“这个问题跟踪器声称已在 PR #N 中修复,#N 是否真的已合并”。最接近的相关工具解决的是其他问题:
| 工具 | 实际检查内容 | 是否读取问题跟踪器 / PR 合并状态? |
|---|---|---|
| ShimGuard | GitHub 问题中引用的“已在 PR #N 中修复”这一说法是否与 PR #N 的实际合并状态相符(并且可以选择检查所引用的代码模式是否已从 HEAD 中消失) | 是,这就是它的全部检查内容 |
| gitleaks / trufflehog | 已提交到源代码中的机密(API 密钥、令牌) | 否,它扫描的是文件内容,而非跟踪器状态 |
| trivy / grype / osv-scanner | 依赖树中已知的 CVE | 否,它扫描的是依赖清单 / 锁文件,而非跟踪器状态 |
| Vanir(Google) | 已知 CVE 的代码特征是否仍存在于目标源码树中 | 否,它从 CVE 查找代码,不会访问 GitHub 问题跟踪器 |
| VFCFinder(北卡罗来纳州立大学,ASIACCS 2024) | 为尚未关联修复的安全公告寻找可能的修复提交 | 方向相反:它会寻找缺失的引用,不会验证已有引用 |
ShimGuard 填补的空白确实存在,并非纸上谈兵。wow-actions/auto-close-fixed-issues 是其他仓库使用的 GitHub Action,它会在 PR 的 closed 事件(而非 merged 事件)发生时关闭问题:无论 PR 是否真的合并,机器人都可能在 PR 关闭时将问题标记为“已修复”。GitHub 自带的 Closes #N 关键字关联机制只会在 PR 真正合并到默认分支后自动关闭问题,因此,这种特定故障模式源自维护者手动发表评论和第三方自动化,而非 GitHub 自身的默认行为。这正是事后无人发现问题的原因。
ShimGuard 是什么?它为何存在?
ShimGuard 是一个 CLI 和库,以 npm 包和 PyPI 包两种形式发布,用于检查 GitHub 问题中声称的修复(“已在 PR #N 中修复”)是否属实。它会检查该 PR 的实际合并状态(并且可以选择检查漏洞代码模式是否仍存在于 HEAD 中)。之所以开发它,是因为通过引用尚未合并的 PR 来关闭问题,是真实发生过的故障模式,而非假设情形:截至本文撰写时,一个拥有 1,000+ 星标的项目 sybil-solutions/codex-shim 有 6 个安全问题以这种方式关闭,且每个问题引用的都是同一个尚未合并的 PR #52。ShimGuard 不会扫描源代码中的机密(相关工具见 gitleaks、trufflehog),也不会对依赖进行通用漏洞扫描(相关工具见 osv-scanner、trivy、grype)。它验证一个具体且范围明确的说法:跟踪器标记的“已修复”是否符合实际情况。
常见问题
ShimGuard 会修改我的仓库或目标仓库吗? 不会。它只会发起只读的 GitHub API 请求(议题、评论、拉取请求,以及可选的文件内容)。它绝不会写入、评论或修改任何内容。
它需要 GitHub 令牌吗?
偶尔使用时不需要。未认证的请求也能正常工作,但受 GitHub 标准速率限制(每小时 60 次请求)。设置 GITHUB_TOKEN 或传入 --token,即可获得更高的认证速率限制(每小时 5,000 次请求),适用于 CI。
什么算是“有引用的修复”?
ShimGuard 会在议题正文及其评论中查找类似“Fixed in PR #52”“fixed by #101”或“resolved in #20”的短语,并提取其中引用的 PR 编号。如果找不到此类短语,结果会是 UNVERIFIED,而不是 MATCH 或 MISMATCH:ShimGuard 从不猜测。
我可以在 CI 中使用它吗?
可以。如果发现任何 MISMATCH,shimguard verify 会以状态码 1 退出,因此 CI 步骤可以直接据此设置门禁。--format json 会生成稳定、可解析的报告,供机器人或仪表板使用。
如果它不扫描 BYOK shim 配置,为什么叫“ShimGuard”?
这个想法最初的定位更宽泛,是一个针对 BYOK(自带密钥)模型 shim 的本地配置安全扫描器。后来范围缩小,聚焦于更明确、更站得住脚的方向:根据实际合并的代码验证跟踪器声明,这也是 v0.1 发布的功能。这个名称反映了项目的起源场景(sybil-solutions/codex-shim,一个 BYOK 模型 shim),而非当前版本并不具备的功能范围。
ShimGuard 能在 Windows、macOS 和 Linux 上运行吗?
npm CLI 要求 Node.js 18 或更高版本(以使用内置的 fetch API),可在所有能运行 Node 的系统上运行,包括 Windows、macOS 和 Linux。PyPI 包要求 Python 3.9 或更高版本,并在其自身的分类器中标明为 OS Independent。这两个包都没有原生或编译型依赖。
ShimGuard 与 gitleaks 或 trufflehog 有什么区别? Gitleaks 和 trufflehog 会扫描文件内容,查找意外提交到仓库中的机密信息,例如 API 密钥和令牌。ShimGuard 完全不会扫描文件内容来查找机密信息——它会检查 GitHub 的议题和拉取请求 API,寻找一种特定的不匹配情况:议题被标记为“在 PR #N 中修复”,但 PR #N 实际上从未合并。这两类工具针对不同的故障模式,可以在同一条流水线中运行而不重叠;有关完整的相邻工具列表(本项目在编写任何代码前核查过),请参阅上文的“对比情况”。
为什么 shimguard --version 显示的数字可能与已安装包的版本不同?
在过去的某些版本中,运行 shimguard --version 显示的版本字符串落后于已安装包的实际版本——src/cli.ts 中传给 commander 的版本字符串,并不总是在 package.json 版本更新的同一发布中同步更新。这只是显示上的不一致,不会影响 verify 的行为。要查看实际安装的版本,请读取包自身的 package.json,或运行 npm view shimguard-cli version。
ShimGuard 会自动扫描仓库中所有已关闭的议题吗?
不会。你需要通过 --issues 38,41,42 传入要检查的具体议题编号;ShimGuard 目前不会自行遍历仓库中所有已关闭议题的历史记录来查找有引用的修复声明。对于大型仓库,请挑选你关心的议题,例如标记为 security 或关联到某个发布里程碑的议题。
我可以在商业产品或付费 CI 流水线中使用 ShimGuard 吗? 可以。ShimGuard 使用 MIT 许可证(参见 LICENSE),允许商业使用、修改和再分发,包括用于付费产品或内部工具,无需支付版税,也不要求将你自己的代码开源。唯一的条件是保留 MIT 声明。
贡献
请参阅 CONTRIBUTING.md。
安全
请参阅 SECURITY.md。
许可证
MIT,参见 LICENSE。
评论
一个开放协议,规定了 AI 应用如何以统一方式连接外部工具与数据源。客户端负责与模型对话,MCP 服务负责提供工具、资源和提示模板,两者通过标准消息通信,同一个服务可以被不同客户端复用。