1. 从security-audit-skill这个命名说起它到底想解决什么问题第一次看到security-audit-skill这个命名我的直觉是这不是一个普通的脚本或者工具包而是一个面向coding agent的能力模块。命名里带skill这个词在当下的智能体生态里通常意味着它是一段可以被 agent 动态加载、按需调用的技能描述 执行逻辑而不是一个需要人工手动跑的命令行程序。换句话说它的目标用户不是坐在终端前的开发者而是正在替你写代码的那个智能体。这件事的意义比表面看起来大得多。过去我们做代码安全审计流程基本是固定的写完代码跑一遍静态扫描工具人工看报告改再跑。这个链路里人始终在环里。但当 coding agent 开始承担越来越多的编码任务之后问题就变了——agent 写完代码谁来审如果还是等人来审那 agent 带来的效率提升就被审计环节吃掉了。security-audit-skill要解决的正是这个断层让 agent 在生成代码的同时具备自我安全审计的能力。我把它理解成一个随身携带的安全顾问。agent 每写完一段逻辑这个 skill 就被触发一次从几个固定的维度去检查有没有引入明显的注入风险、有没有硬编码的敏感信息、依赖版本有没有已知问题、权限边界是不是开得太大。它不追求替代专业的安全团队而是把那些低级但高频的问题挡在提交之前。适合谁来参考这篇内容三类人。第一类是正在搭建 coding agent 工作流的工程师想知道怎么把安全能力嵌进 agent 的循环里第二类是团队里负责代码质量的人想给现有的 agent 加一道安全闸第三类是对智能体技能设计感兴趣的开发者想看看一个skill从设计到落地要考虑哪些东西。下面我会按我实际搭建这类 skill 的思路把每个环节拆开讲。2. 为什么安全审计要以skill的形态存在而不是一个独立工具2.1 独立扫描工具在 agent 工作流里的尴尬位置先说一个我踩过的坑。早些年我给团队的 CI 加过一堆静态扫描工具规则配得很全跑得也稳。但当我把 coding agent 接进来之后发现这套东西几乎失效了。原因很朴素agent 的产出是流式的它可能在一个会话里改了十几个文件而 CI 扫描是批式的要等所有改动提交后才跑。等报告出来agent 早就跑到下一个任务去了上下文丢了改起来成本极高。更麻烦的是独立工具的输入输出是给人看的。一份扫描报告动辄几百行agent 读起来费劲还容易抓错重点。它需要的是结构化的、带明确修复建议的、能直接喂回给它自己继续处理的信号。这就是skill形态的第一个价值它不是给人看的报告生成器而是给 agent 看的决策输入。2.2 skill 的三个本质特征可加载、可组合、可回灌我总结下来一个合格的 security-audit-skill 应该具备三个特征。可加载意味着它平时不占资源只在需要的时候被 agent 拉起来。这跟常驻的守护进程完全不同。agent 在写业务逻辑时不需要它只有在生成涉及输入处理、数据库操作、文件读写、网络请求的代码时才把审计能力加载进来。这种按需加载的设计直接决定了 skill 的描述文件要写得极其精准否则 agent 根本不知道该在什么时候调用它。可组合意味着它不是一个孤立的检查器而是能和 agent 的其他能力串起来。比如审计发现了一个 SQL 拼接问题skill 不只是报错还要能把这里应该用参数化查询这个修复意图传递给 agent 的代码生成模块让它直接改。这就要求 skill 的输出格式和 agent 的内部协议对齐。可回灌是我认为最关键的一点。审计结果必须能作为下一轮生成的输入。很多团队做安全审计止步于发现问题但 agent 场景下发现问题只是中间态真正的闭环是发现—修复—复验。skill 要支持这种多轮交互而不是一次性输出。2.3 一个反直觉的结论审计规则越少越好这里说个可能让很多人意外的观点。我一开始给 skill 塞了上百条规则覆盖各种边角情况结果 agent 的响应质量反而下降了。原因是规则太多agent 在判断这段代码要不要触发审计时就开始犹豫触发之后又要在一堆规则里挑重点注意力被稀释了。后来我砍到只剩核心的十几条聚焦在注入类、敏感信息泄露类、权限越界类、依赖风险类这四个方向效果立刻好转。这背后的逻辑是agent 的上下文窗口是稀缺资源审计 skill 占用的每一分注意力都是从业务逻辑里抢来的。与其追求规则全覆盖不如把最高频、最高危的问题盯死。剩下的交给专业的深度扫描工具在 CI 阶段兜底。提示设计 skill 规则时先问自己这条规则触发后agent 能不能自己修。如果修不了需要人工介入那它就不该放在 skill 里而应该放在人工审计环节。3. 拆解 security-audit-skill 的核心能力模块3.1 输入识别判断这段代码值不值得审skill 被调用时第一件事不是急着扫描而是判断输入。我见过太多实现一上来就对所有代码无差别扫描结果大量误报把 agent 带偏。正确的做法是先做一轮轻量的输入分类。我的做法是给 skill 定义一个敏感面清单代码里是否出现了用户输入的直接拼接、是否出现了数据库查询构造、是否出现了文件路径拼接、是否出现了外部命令调用、是否出现了密钥或令牌字面量。只要命中其中任意一项才进入深度审计。这个前置判断本身很轻基本就是模式匹配但它能把无效审计降低一大半。这里有个细节值得说判断逻辑不能太死。比如同样是字符串拼接SELECT * FROM table和Hello, name的风险等级完全不同。前者是注入高危后者基本无害。所以输入识别阶段要带上上下文感知看这个拼接结果最终流向哪里。流向数据库执行接口的重点标记流向日志或界面的降级处理。3.2 规则引擎把安全知识翻译成 agent 能懂的形式规则引擎是 skill 的心脏。但它的写法跟传统静态分析工具完全不同。传统工具用正则或者 AST 匹配输出的是第几行有问题。而 skill 的规则要输出的是**这里有什么风险 为什么 怎么改** 三件套。我举个具体例子。检测硬编码密钥这条规则传统写法是匹配一串高熵字符串。但 agent 拿到第 42 行疑似密钥这个信息它不知道该干嘛。skill 的规则应该写成识别到形如api_key sk-...的赋值判定为敏感信息硬编码风险是密钥可能随代码泄露修复建议是改为从环境变量读取并给出具体的读取代码模板。这样 agent 拿到之后能直接执行修复。规则的本质从检测器变成了知识包。这也是为什么我前面说 skill 不是工具而是能力——它承载的是可执行的修复知识而不只是判断逻辑。3.3 输出协议让审计结果能被 agent 直接消费输出格式这块我强烈建议用结构化数据而不是自然语言描述。原因很简单agent 后续要基于这个结果做决策自然语言有歧义结构化数据没有。我用的格式大致是这样每条发现包含type风险类型、severity严重程度、location位置、evidence证据片段、remediation修复建议、confidence置信度。其中confidence这个字段特别有用它让 agent 知道哪些发现是板上钉钉哪些是疑似。对于高置信度的问题agent 可以直接改对于低置信度的agent 可以选择标记出来让人确认。severity的分级也要克制。我见过有人分五级结果 agent 根本分不清 P2 和 P3 的区别。我一般只用三级阻断级必须改否则不能提交、警告级建议改agent 自行判断、提示级记录备查。分级越少agent 的决策越干脆。3.4 修复回灌审计的终点是改完并复验前面反复强调闭环这里说具体怎么实现。skill 输出发现之后agent 进入修复模式改完代码skill 要能对改动后的代码再跑一遍确认问题消失。这个复验环节不能省因为 agent 的修复经常是看起来对了但没完全对。我遇到过好几次agent 把字符串拼接改成了参数化查询但参数传的顺序错了或者漏了某个字段。如果不复验这种半吊子修复就混过去了。复验的逻辑很简单对同一位置重新跑一遍规则如果原问题消失且没有引入新问题标记为已修复否则继续循环。循环次数要设上限一般三轮还没搞定就升级为人工介入。4. 把 skill 接进 coding agent 的实际操作路径4.1 触发时机在哪个环节插入审计最合适触发时机选错整个 skill 的价值就打折。我试过三种方案说说各自的利弊。第一种是生成后立即触发。agent 每写完一个文件就审一次。优点是问题发现得早上下文新鲜缺点是触发太频繁拖慢整体速度而且很多中间态代码本来就不完整审了也是白审。第二种是任务完成后触发。agent 完成一个完整任务再统一审。优点是效率高审的是完整逻辑缺点是如果任务很大问题积累得多修复起来上下文跨度大。第三种是我最终采用的关键节点触发。在 agent 生成涉及敏感操作的代码块时触发比如写数据库访问层、写接口参数处理、写文件操作时。这些节点是安全问题的重灾区也是上下文最完整的时刻。非敏感代码不触发整体开销可控。具体怎么判断关键节点我在 skill 的描述里定义了几个触发信号代码中出现了外部输入变量、出现了数据库或文件系统 API、出现了网络请求构造、出现了权限判断逻辑。agent 在生成过程中命中这些信号就调用 skill。4.2 上下文准备给 skill 喂什么料skill 要审得准输入不能只有当前这段代码。我的经验是至少要给三样东西当前代码片段、相关的类型定义或接口签名、以及这段代码的调用方信息。为什么需要调用方信息因为很多安全问题取决于数据流向。一个函数内部看起来人畜无害但如果它的参数来自用户输入且没做校验那问题就大了。只给 skill 看函数体它判断不出来。把调用链的关键部分一起喂进去skill 才能做出准确判断。这里有个实操技巧不要把所有上下文一股脑塞进去那样会撑爆窗口。我一般只取直接调用方和直接被调用方这一层再往外的用摘要代替。摘要里保留数据来源和信任级别的标注比如参数来自 HTTP 请求体未经校验。4.3 结果处理agent 拿到审计结果后该怎么走agent 拿到 skill 的输出后我给它定了三条处理路径。阻断级问题立即停止当前生成进入修复模式。修复完成后必须复验通过才能继续。如果连续三轮修复失败把问题抛给用户附上 skill 的原始发现和 agent 的修复尝试记录。警告级问题agent 自行判断。如果修复成本低且不影响业务逻辑直接改如果涉及架构调整或者需要业务决策标记出来继续往下走最后统一汇报。提示级问题只记录不打断流程。这些通常是风格问题或者低风险项攒到任务结束时一起给用户看。这套路径的关键是让 agent 有自主权但保留升级通道。全自动修复容易改出问题全人工确认又失去了 agent 的意义。分级处理是平衡点。4.4 一个完整的交互示例假设 agent 正在写一个用户查询接口生成了这样一段代码def get_user(username): query SELECT * FROM users WHERE name username return db.execute(query)skill 被触发后输出结构化发现类型为 SQL 注入严重程度为阻断级证据是字符串拼接构造查询修复建议是使用参数化查询置信度为高。agent 收到后进入修复模式改成def get_user(username): query SELECT * FROM users WHERE name %s return db.execute(query, (username,))然后 skill 复验确认拼接消失、参数化到位标记为已修复。整个过程 agent 不需要人工介入但每一步都有记录可查。5. 实测中暴露的问题与我的应对5.1 误报agent 被假问题带偏误报是这类 skill 最大的敌人。我统计过一轮初期误报率能到四成agent 大量时间花在修根本不存在的漏洞上。误报主要来自两类一是模式匹配太宽泛把安全的写法也标红了二是缺乏上下文把已经做过校验的输入当成未校验。应对办法有两个。第一是引入白名单机制对于团队内部约定的安全封装函数比如统一的输入校验工具、统一的查询构造器skill 识别到这些函数就跳过检查。第二是提高置信度门槛只有置信度高的发现才触发阻断低置信度的降级为提示。这两个措施下来误报率压到了可接受的范围。5.2 漏报那些 skill 看不见的角落漏报比误报更危险因为它给人虚假的安全感。我发现的漏报主要集中在跨文件的逻辑漏洞上。比如单个文件里每处输入都校验了但两个文件之间的数据传递环节漏了校验这种问题单文件审计根本发现不了。我的应对是给 skill 加一个跨文件数据流追踪的轻量能力。不追求完整的污点分析只追踪敏感数据从入口到危险操作的路径中间经过的每个函数都检查是否有校验。这个能力实现起来不复杂但能堵住相当一部分漏报。5.3 性能审计拖慢了 agent 的响应性能问题在任务量大时特别明显。我测过如果每个文件都全量审计agent 的整体响应时间会增加三到五成。用户体感就是变卡了。优化思路是分级审计。第一级是快速模式匹配毫秒级完成过滤掉大部分安全代码第二级是深度审计只对第一级命中的代码跑做上下文分析。这样大部分代码走快速通道只有少数敏感代码走深度通道整体开销降下来了。5.4 规则维护安全知识怎么持续更新安全威胁在变skill 的规则也得跟着变。但规则维护是个苦活写规则的人得懂安全还得懂 agent 的交互协议。我的做法是把规则和引擎分离规则用声明式的方式写引擎负责解释执行。这样安全专家只需要写规则不用碰引擎代码。规则文件我用 YAML 格式每条规则包含匹配模式、风险描述、修复模板、严重程度。新增一类威胁加一条规则就行不用改引擎。这个设计让规则的迭代速度提升了很多。6. 让 skill 真正好用的几个设计细节6.1 修复建议要具体到能直接抄这点我反复强调过但值得再展开。agent 不是安全专家它拿到这里存在注入风险这种描述只能靠猜来修。但如果拿到的是把字符串拼接改为参数化查询参数以元组形式传入参考模板如下它就能直接执行。所以 skill 的每条规则都要配一个可执行的修复模板。模板里用占位符标出需要替换的部分agent 填充即可。模板的质量直接决定了修复的成功率。我维护了一套模板库覆盖常见的修复场景规则引用模板而不是每次现写。6.2 置信度要诚实不能虚高置信度这个字段很多实现喜欢往高了标觉得这样 agent 更重视。但这是自欺欺人。置信度虚高agent 会对所有发现都当阻断级处理结果就是误报的破坏力被放大。我的原则是只有模式明确、上下文清晰、没有歧义的发现才给高置信度。任何需要推断的一律降级。宁可让 agent 多问一句也不要让它改错。置信度诚实agent 的决策才靠谱。6.3 给 agent 留申诉通道这个设计比较特别。agent 在修复过程中如果认为某个发现是误报可以提交申诉附上它的理由。skill 收到申诉后重新评估如果确认是误报就撤销发现并记录用于后续优化规则。这个通道的价值在于它让 skill 有了自我修正的能力。agent 在实际使用中遇到的误报通过申诉反馈回来规则就能持续优化。我上线这个机制之后误报率又降了一截。6.4 审计日志要可追溯每次审计的输入、输出、agent 的处理动作都要留日志。这不是为了合规而是为了排查问题。当 agent 改错了代码你得能回溯到是哪次审计、哪条规则、给了什么建议导致的。没有日志这种问题根本查不清。日志的粒度我控制在每次 skill 调用一条记录包含时间戳、触发原因、输入摘要、发现列表、agent 动作。量不大但关键时刻能救命。7. 关于这套 skill 设计思路的一点个人体会搭这套东西的过程中我最大的体会是安全审计 skill 的本质不是检测而是教育。它真正在做的事情是把安全知识以 agent 能理解的方式传递过去让 agent 在生成代码时就带着安全意识。检测只是手段让 agent 学会写出安全的代码才是目的。另一个体会是不要追求完美。我一开始想把所有安全问题都覆盖结果 skill 变得臃肿、缓慢、误报高。后来做减法聚焦高频高危场景反而效果好。安全是个持续的过程skill 能挡住大部分常见问题剩下的交给专业工具和人工这个分工是合理的。最后一个实操建议先跑起来再优化。不要等规则写全了才上线先用最核心的几条规则跑通闭环看看 agent 的实际反应再根据暴露的问题迭代。我见过太多团队卡在规则还没写完的阶段结果一直没上线。安全能力这东西有总比没有强哪怕一开始只挡一个 SQL 注入也是实实在在的收益。