用 Claude Code 一段时间之后,配置会自己往乱的方向漂移:装过的技能有的再没用过、规则文件为了图方便用了强制常驻的加载方式、权限白名单里的通配符越写越宽,因为宽通配确实省事——每次都要弹窗确认是真的烦。花了两天时间做了一轮系统体检,把”能用”和”图省事”的地方,往”经得起审”上收紧了一遍。
第一天:/doctor 清理
先跑了内置的配置体检,走了四轮流程:数据扫描 → 跟已有的项目记忆对照 → 问用户几个关键问题 → 逐项功能分析判断去留。
结果:
- 8 个技能被禁用——零使用记录,且跟现有工作流重叠或完全无关。同时也确认了另一批零使用但该留的技能:Obsidian 相关的几个,因为跨设备笔记同步的工作流依赖它们;办公文档处理类的,因为经常要生成 Word/Excel/PPT;
mcp-builder,因为有个正在用的项目在靠它维护。零使用不等于该删,得对照真实依赖判断。 - 规则加载方式改成懒加载。原先几份跟前端/TypeScript 相关的规则用
@import强制常驻,不管当前有没有在碰这类文件,都会占掉一块 context。改成按文件类型(pathsfrontmatter)触发的懒加载,只有真的在改对应文件时才会读进来。 - 两份文档转成正式技能,跟已有的技能目录统一收口,不再是两个格式不一致的散装文档。
清理过程里顺带发现一个缺口:规则文件里点名引用了一批子代理(架构规划、TDD、安全审查等),但当初装规则的时候没有配套装这些代理——规则在喊人,人没到场。补齐了 8 个对应的子代理。
第二天:权限白名单收紧
复查了允许自动执行的命令白名单,发现一堆过宽的通配:解释器命令、docker *、find * 这类。宽通配的问题不只是”权限给多了”——它等于预先批准了在这个通配范围内的任意代码执行,一旦遇到提示注入场景,这道本该有人工确认的闸门直接失效。全部换成精确的子命令或者完整命令。
一个真实的坑:写错了通配格式
配置沙箱豁免名单时,图快写成了裸命令名(比如 docker),但沙箱机制实际要求的是通配格式(docker *)。这两者字符串不匹配,导致全部相关豁免规则一条都没生效——命令照样按最严格的规则跑,之前一直以为”已经放行了”的东西,其实从没生效过。改成正确格式、跑一次新会话验证,才算真的修好。这种”以为配置生效、实际压根没生效”的坑最难受,因为表面看起来一切正常,直到专门去验证才会暴露。
域名白名单不是硬边界
一开始以为沙箱网络层的域名白名单是硬拦截——不在名单里的域名请求会被直接挡掉。实测发现不是这样:当前的自动执行权限模式底下有个分类器在做代批,白名单外的域名实际上是能通的,只是过一道分类器判断。
评估之后决定接受这个现状,没有再往更严格的方向锁(比如托管级别的域名硬限制)。理由:白名单里本来就有一个通用代码托管域名,本身就是一条合法的对外通道,再去堵零散小域名边际收益不大;而分类器本身经过测试,确实能拦住往外读密钥这类高风险场景。安全投入要花在真正值钱的地方,不是把所有缝隙都焊死。
给高价值目标加了读取层面的硬拒绝
除了执行层面的白名单,还单独给几类高价值目标加了读取工具级别的拒绝规则:密码库的数据目录、备份暂存区、SSH 私钥、加密密钥、系统级敏感配置。这些之前理论上是可以被直接读到的,现在读取工具本身会先拒绝,不依赖”AI 应该不会去读”这种软约束。
沙箱试点
为了在收紧权限的同时不把每次操作都变成弹窗确认,开了一个沙箱模式试点:独立网络命名空间 + 域名白名单 + 沙箱内自动放行常规命令。计划观察一周,看会不会误伤合法操作。
已经摸到一个已知限制:沙箱是独立的网络命名空间,从里面 curl 本机回环地址,连不到宿主机上跑着的其他服务——这不是配置错误,是网络隔离本身的设计所致,遇到这种情况得走”逃生舱口”(临时脱离沙箱重跑一次,同时弹确认)。
写在最后
这轮体检没有新功能,全是把用了一段时间之后自然堆出来的”权宜之计”重新审一遍。安全和配置卫生这种事不像功能开发,做完就完了——不主动去查,只会朝着更松、更省事的方向慢慢漂移。定期回头体检一次,比一次性做到完美更重要。