一件事常被忽略:现在的「开发环境」里住着一堆能执行命令、能读文件、能拿到凭证的程序。编码智能体本身如此,MCP 服务更是如此——不少服务默认就能读整个用户目录;钩子更直接,事件一到就执行,而且不会弹窗问你要不要。GitLab 最近那份内部安全评估讲的就是这个方向的风险:一个数字在沙箱允许列表里的包代理,成了代理逃出沙箱的桥。

要管理这些东西,第一步是先知道自己有什么。geiger 把这一步压成一条命令,它只读配置与目录,不执行任何插件、不联网、不写文件(除非你明确指定 --json 输出路径),凭证只报键名、文件与「看起来像哪一类密钥」,不报值。要求只有 Node.js 18 以上,零依赖。

第一步:跑一遍,先看清有什么

npx geiger-scan

# 机器上还没有 Node 时(Windows / macOS / Debian 系)
winget install OpenJS.NodeJS.LTS
brew install node
sudo apt install nodejs npm

npx 会临时拉取 geiger-scan 包执行,不需要全局安装、不需要管理员权限、也不需要账号。输出把发现按生态分组,大致长这样:claude-code 分组下列出 Claude Code 本体、它配置的 MCP 服务、以及所有会「触发即执行」的钩子;每一行后面挂着能力标签和证据路径。

第二步:生成 HTML 报告,逐条复检

npx geiger-scan --html report.html

# 项目目录里通常还有一份独立的配置,一并扫进来
npx geiger-scan --path D:\repo1 --path E:\repo2 --html report.html

终端输出适合快速扫一眼,HTML 报告适合坐下来逐条看:每条发现都带「这是什么、从哪来、能做什么、去哪核对」四段信息。来源字段里出现 UNKNOWN-ORIGIN 的条目要优先看——它意味着工具无法判断这个配置来自注册表、商店、git、本地脚本还是远程服务器,通常对应手工改过的配置文件或者来源不明的脚本。

第三步:把能力标签翻译成风险

  • EXECUTES:能执行代码。单个标签不算结论,它和下一个标签同时出现时才真正要紧
  • HOLDS-SECRETS:配置里放着凭证。报告只给键名与文件,不给值
  • BROAD-FILESYSTEM:能访问大范围目录(例如整个用户目录),常见于默认配置的 MCP 服务
  • BROAD-WEB / NETWORK:能出网,数据外泄与供应链风险都从这里走
  • 钩子(hooks):事件触发时执行,不经过确认,所以即使出自你信任的插件也要单独看一遍

把这份清单读成风险的方式很简单:先找「能执行代码 + 持有凭证」的交集,再找「能执行代码 + 大范围文件系统 + 能出网」的组合。前者一旦被恶意提示词或供应链污染利用,就是直接拿数据;后者是数据外泄路径。只满足单个标签的条目,多数可以留到第二批发落。

第四步:留基线,用差异盯住变化

# 第一次盘点后存一份基线
npx geiger-scan --json baseline.json

# 之后每次盘点与基线对比
npx geiger-scan --diff baseline.json

# 用于 CI 或提交前卡口:只要能执行代码或持有凭证的条目存在,就返回退出码 2
npx geiger-scan --strict

风险往往不是一次装出来的,而是一次次加进来的:今天装个扩展、明天接个 MCP、后天某个服务升级后默认权限变了。--diff 让变化可见,--strict 让变化在流水线里变成硬约束。要特别注意 --strict 的语义是「只要有能执行代码或持有凭证的条目就非零退出」,适合放在共享构建机与发布流程里,个人开发机上更适合当作定期提醒而不是阻断。

第五步:把发现变成收敛动作

  • 清掉不再使用的 MCP 服务与扩展:装机时顺手装的,多数只用过一次
  • 把配置里的长期凭证挪到环境变量或系统凭据管理器,配置只留引用
  • 给能读整个用户目录的服务收窄路径范围,改成只读项目目录
  • 对于会执行代码的钩子,逐个确认它的行为来源;不能确认来源的直接移除
  • 用 --home 扫描其它用户配置或挂载的镜像,用 --path 覆盖开发项目里的局部配置
# 扫描另一个用户配置 / 挂载镜像
npx geiger-scan --home C:\Users\other --json other-profile.json
盘点报告的用处不在于知道自己装了多少东西,而在于知道哪些东西同时能执行代码、又能拿到凭证——那个交集就是必须先处理的清单。