资讯详情

资讯详情

AI编程助手安全审计Skill:从越权漏洞到CI/CD集成

去年我在维护一个内部服务时代码评审阶段发现支付回调接口埋着一个越权漏洞。更尴尬的是这段有问题的代码是AI编程助手生成的它能秒级写完业务逻辑却完全没意识到自己在处理敏感资源时需要校验归属权。从那天起我开始琢磨一件事能不能把安全审计的能力做成一整套Agent随时可调用的“技能包”让AI不光会写代码还能在写之前、写之后主动帮我把安全隐患筛一遍。于是就有了security-audit-skill这个项目。这篇文章会把整个过程完整摊开来讲Skill在Agent生态里到底是什么、为什么安全审计特别适合做成Skill、一个可用的security-audit-skill内部结构长什么样、我是怎么在本地仓库和CI流水线里实测的以及中途踩过的误报、漏报、上下文丢失这些坑。如果你正在用Codex、Claude、OpenCode这类工具写代码又不想把安全问题全部押在事后人工评审上这篇内容应该能帮你少走不少弯路。1. security-audit-skill到底在解决什么问题1.1 代码安全审计的痛点与现有工具的边界代码安全审计这件事传统上基本靠三类手段静态分析工具SAST、依赖漏洞扫描、人工代码评审。SAST类工具像Semgrep、CodeQL、SonarQube优点是规则严谨、覆盖广但问题是误报率不低而且很多规则只能抓“特征”抓不住业务流程里的逻辑漏洞。比如前面说的越权问题工具能看到你调用了getOrderById但它不知道这个订单是不是属于当前登录用户这种上下文只能靠人去判断。人工评审倒是能理解业务逻辑但成本高、周期长而且在小团队里往往被压缩成“上线前走个过场”。依赖漏洞扫描解决的是供应链问题对自研代码的逻辑缺陷基本无能为力。你会发现传统工具链在“静态特征检测”和“业务逻辑理解”之间存在一条明显的空档而大模型恰好擅长理解意图和上下文。这就是我决定把安全审计做成Agent Skill的出发点把SAST的规则严谨性和LLM的上下文理解能力结合起来。1.2 为什么是Skill而不是Plugin或者Agent热词区里有人在问“skill和agent的区别”这确实是很多人刚接触这个概念时最容易混淆的地方。我的理解直接说Agent是一个能做决策、能循环执行任务的“操作者”Skill是给这个操作者预装的“能力包”。Agent负责拆解任务、调用工具、编排步骤Skill负责告诉Agent“面对某类问题时你有一整套成熟的应对流程可以按这个来”。如果你把这个能力做成插件它会偏向于提供一个具体的函数或接口调用方得自己决定什么时候用、怎么用主动权在调用方手里。但做成Skill主动权在Agent手里当它发现当前任务涉及安全检查时会自动加载对应流程。Plugin是“你叫它它才动”Skill是“Agent根据任务上下文主动想到用它”。至于把它做成一整个独立的Agent那就太重了——安全审计通常只是研发流程的一个环节做成Agent反而难以和现有的Codex、Claude Code、OpenCode工作流无缝衔接。所以security-audit-skill的定位很清晰它不是替代人类安全工程师的独立系统而是给AI编程助手装上的一套“安全审查工作记忆”。代码写完了或者准备提交了Agent能自觉进入审计模式把可疑点一处处列出来给你看。2. 拆解Skill的运行机制Agent怎么“学会”做安全审计2.1 Skill的核心组成SKILL.md与脚本资产的协作关系我在GitHub上参考过不少Skill项目也自己翻过一批skill技能库发现一个靠谱的Skill基本都由两大部分构成面向Agent的指令文件和面向具体任务的脚本资产。指令文件通常叫SKILL.md它的作用不是给人读的文档而是给LLM的“工作手册”。脚本资产则是实际干活的代码比如扫描器、规则文件、报告模板。这两者的关系我打个比方SKILL.md是带班组长的工作指令告诉Agent“这次任务的流程分几步、每步有什么标准、遇到什么情况要停下来”脚本资产是工具箱里的扳手和螺丝刀Agent按指令判断该拧哪个螺丝时就抽出对应工具去执行。没有SKILL.mdAgent不知道什么时候该用这批脚本没有脚本资产Agent只能靠自己的知识硬写规则质量完全不可控。我见过一些人写的SkillSKILL.md只有三五行“你是一个安全审计专家”没有任何流程和约束实际用下来Agent基本不会触发偶尔触发了也只是泛泛而谈给不出具体文件和行号。真正好用的SkillSKILL.md一定要写得像SOP标准作业程序一样明确。2.2 触发与编排让审计动作在合适的时机自动出现Skill能不能被Agent自动想起来关键在SKILL.md里怎么描述触发条件。这部分的写法直接决定你的Skill是“救命工具”还是“摆设”。我在多次实测后总结出一条经验触发条件描述要覆盖“任务类型”和“信号词”两层。任务类型层是告诉Agent“这类任务你应该用我”比如“代码审查”“安全审计”“上线前检查”“提交前自查”。信号词层是更细的提示比如“SQL查询”“用户输入”“鉴权”“Token”“加密”“依赖”“日志脱敏”等等。当用户对Agent说“帮我review一下这个改动”Agent看到“review”这个词再结合当前改动的代码涉及用户输入拼接查询就会主动联想到该加载security-audit-skill。编排层同样重要。Skill一旦被激活Agent不能上来就乱扫一通得有步骤。我在SKILL.md里明确规定了执行顺序先收集项目结构和变更文件列表再做静态规则扫描然后让模型对扫描结果做上下文研判最后输出结构化报告。这个顺序一旦固定下来审计结果的可复现性会大幅提升。我刚开始没写执行顺序结果Agent每次跑的流程都不一样有时候先分析业务逻辑有时候先扫依赖文件报告格式五花八门根本无法横向对比。3. 手写一个可复现的security-audit-skill结构3.1 目录骨架与核心清单如果只是想要一个能跑的Skill不需要搞得很复杂。我的第一个可用版本包含一个目录、三个文件结构如下security-audit-skill/ ├── SKILL.md └── scripts/ ├── audit_rules.json ├── scan.py └── report_template.mdSKILL.md是Agent的行为指导告诉它什么场景下激活、按什么流程审计、需要注意哪些约束比如“不要在没有证据的情况下断言漏洞必须给出文件路径和行号”。audit_rules.json是静态规则的集合把常见高危模式按类别组织好Agent可以加载它做初步筛查。scan.py是一个轻量脚本负责做两类事情一是列出仓库里的关键文件清单二是调用规则文件跑一轮正则和AST风格的模式匹配把可疑代码段定位到文件和行号。report_template.md是输出的标准模板保证每次审计报告格式一致方便后续处理和归档。这个结构理论上可以跑在任何支持Skill机制的Agent上。我实际测试过Codex和OpenCode也有人在Claude Code里装过类似的兼容性整体没问题。核心思路就是不要让Agent自己从零编一套审计流程而是把所有流程和规则固化下来Agent只需要按图索骥。3.2 检测规则怎么写才不被Agent忽略规则文件是security-audit-skill的灵魂。写得不好Agent加载了也不当回事。我第一版规则只有一张简单的关键词列表比如“password”“token”“select”结果Agent扫描的时候把所有带这些词的代码全标红了报告完全没法看。后来我改成了结构化规则每一条包含规则ID、风险类别、严重级别、匹配模式、上下文判断要点、修复建议。这里贴一个我实际在用的例子{ rule_id: AUDIT-SQLI-001, category: injection, severity: critical, patterns: [ executeQuery, executeUpdate, rawQuery, $query, \\$qb-expr() ], context_hints: [ 判断拼接进SQL的字符串是否来自HTTP请求参数, 检查是否使用了预编译语句如果没有判定为可疑, 如果SQL片段里有直接拼接的变量名必须标记出来 ], recommendation: 使用参数化查询或预编译语句禁止直接拼接SQL }关键点在于context_hints这一段。我的做法是脚本扫描出候选位置后把这一段的代码片段连同context_hints一起交给LLM。Agent读到“来自HTTP请求参数”“是否预编译”这两个提示就能基于上下文做出判断而不是机械地见executeQuery就报警。这样一套组合拳下来误报率明显下降报告里能说出“为什么可疑”而不只是“这里有这个函数”。还有一点值得强调规则描述里必须明确“什么时候不要报”。比如很多代码里写日志时会打印用户邮箱这不算敏感信息泄露但如果打印的是身份证号、支付账号就要标记为中等风险。LLM需要这些边界才能做出准确判断别让它猜。3.3 输出报告格式设计审计报告格式是我调整次数最多的部分。一开始Agent自己生成markdown报告结构还算清晰但不同轮次跑出来的字段名不统一有的写“严重级别”有的写“风险等级”对接到后续工单系统时很麻烦。后来我干脆用模板把它定死报告必须包含以下区块审计概览项目名、审计时间、扫描文件总数、问题总数、按严重级别分布严重/高/中/低问题列表每条包含问题ID、风险类型、严重级别、文件路径、行号、问题描述、上下文证据、修复建议未发现问题的重点区域按SKILL.md里的关键词清单列出哪些高风险区域已经排查过且未发现问题方便评审人知道Agent确实覆盖了哪些范围补充观察Agent在上下文研判中发现但不完全确定的问题单独放一个“低置信度提示”避免混入正式问题造成干扰报告格式定死之后还有一个额外的好处你可以写一个后续任务让Agent把报告内容自动填到某个表格或者Issue模板里字段能一一对应上。安全团队跟进问题的时候不用再从一段散文里手动提炼信息。4. 实测链路从本地代码仓库到审计报告4.1 环境准备与Skill装载我先说明一下测试环境机器是MacBook Pro安装了Codex的CLI版本同时也用OpenCode跑过一遍两个环境下的表现基本一致。Skill的装载方式不同工具略有差异但原理相同——把Skill目录放在Agent能扫描到的配置路径中或者用支持的命令手动装载。以Codex为例你可以在配置里指定skill目录也可以直接在会话中用命令加载某个skill。这里有一个新手特别容易踩的坑装完Skill之后一定要开一个新会话验证Agent能否正确识别。Agent的上下文是会话级的你在旧会话里装好的Skill旧会话可能不会主动刷新加载容易误以为“Skill坏了”。我一般会在装完后问一句“你现在有哪些可用的skill分别适用什么场景”让Agent复述一遍确认它真的读到了SKILL.md里的内容而不是我还停留在理想状态。4.2 完整执行过程与结果解读我用一个模拟了常见漏洞的测试仓库来做演示。仓库是Python写的一个Flask应用含一个登录接口、一个订单查询接口、一个数据库访问模块。我在里面人为埋了几个典型问题登录接口里SQL拼接、订单查询接口没校验用户归属、日志里打印了明文密码字段、requirements.txt里出现了一个存在已知漏洞的旧版本库。实际执行时我让Agent“review这个项目的代码重点关注安全问题”。Agent成功加载了security-audit-skill然后按SKILL.md流程先扫描文件清单随后调用scan.py跑规则找到可疑位置再结合上下文逐条研判。最后产出的报告里四个问题全部命中并且SQL注入那条被标成了严重级别越权那条标为高日志脱敏问题标为中依赖漏洞标为高。文件路径、行号、修复建议全部对得上。有个细节让我印象很深Agent在研判越权问题时自己去看了一眼这个接口路由有没有装饰器做登录校验发现只有登录校验没有归属校验然后在报告里写了一条“虽然接口要求登录但并未校验订单归属存在IDOR风险”。这说明只要上下文给得足LLM是真的能理解逻辑漏洞而这恰恰是传统SAST工具最难啃的部分。4.3 误报、漏报与上下文丢失的应对实测中不可能全是顺利的。我遇到的第一类问题是误报典型场景是测试代码里大量使用Mock数据字符串里包含“select * from users”这种SQL片段但其实是测试用例不是真实查询。刚开始Agent会把这些标成“疑似SQL注入”。后来我在SKILL.md里加了一条约束“如果可疑代码位于test/、tests/、mock/、fixtures/目录应降级为观察项不计入正式问题列表。”误报率一下降了七成。第二类问题是漏报多发生在代码文件特别多的时候。Agent受上下文窗口限制可能只仔细看了前几个文件后面的文件草草带过。我后来在SKILL.md里明确要求“先扫描项目结构如果文件数量超过20个必须分批审计每一批都要在报告中记录覆盖状态。”同时要求scan.py输出一份完整文件清单Agent审计完一批勾选一批避免遗漏。第三类也是最有代表性的问题上下文丢失。有一次在一个大型Java项目里跑Agent分析到一半突然忘了自己加载过security-audit-skill开始用普通“代码解释”模式跟我聊天报告格式完全走样。排查了半天发现是因为SKILL.md太长Agent读到后面注意力被其他任务占用了。解决办法是把SKILL.md精简到核心SOP把冗长的规则细节全部挪到audit_rules.json和scripts里让SKILL.md只承担“流程指挥”的角色。这个调整之后上下文丢失的情况明显减少。5. 从“能用”到“好用”的进阶经验5.1 让审计规则可配置化跑到第二周我开始不满足于固定的内置规则。不同项目的风险侧重点差别很大给支付系统做审计重点看金额计算、幂等性、回调验签给内容社区做审计重点看XSS、用户生成内容的展示转义给内部管理系统做审计重点看越权和敏感数据查询。由于每个项目的代码风格和业务形态不一样固定规则很难满足所有场景。我的做法是引入一个audit_profile.json配置层允许按项目覆盖规则。每个项目根目录下放一个审计配置文件里面可以指定启用哪些规则类别、额外添加哪些关键词模式、忽略哪些目录。scan.py在运行时先读取项目配置再叠加内置规则形成一份“项目专属规则集”。SKILL.md里也写了一段如果发现项目根目录有audit_profile.json优先使用它覆盖默认规则。这样做的收益很直接不同团队可以直接共享同一个Skill但每个项目有自己的审计策略。规则集不再是僵死的而是随项目演进的资产。有同事问我这算不算把Skill变成配置驱动的框架我说对这个阶段你已经不是在“写死规则”了而是在建设一套组织级的安全审计基线。5.2 和CI/CD流水线的结合本地跑通之后我很快意识到真正发挥价值的地方是CI流水线。人的自觉性不可靠但流水线不会偷懒。我的做法是写了一个小的命令行入口能让Agent在离线环境下对指定代码变更集运行审计。注意CI环境一般没有交互式会话所以命令行入口必须支持非交互模式接收一个diff或提交范围输出报告文件。实际流水线里我是这样接的在Pull Request触发后CI执行一次“新增或变更文件的增量审计”把报告上传到GitHub Action的artifact如果有严重级别的问题直接让CI标记为失败阻止合并。最开始团队成员担心误报会拖慢合并速度于是我加了一个“细微阈值”配置只有严重和高等级问题才阻断流水线中低等级问题只出现在报告里提醒开发者处理。这样既守住了底线又不至于让AI审计变成开发流程的瓶颈。这套流程跑了一个多月最直观的效果是人工评审时不再需要花时间找低级的注入问题可以把注意力放到业务逻辑和架构合理性上。AI审计把“下限”兜住了人工评审专注“上限”的优化。5.3 我踩过的坑与最终建议最后集中说几个踩过的坑。第一个坑是Skill里塞了太多领域知识导致SKILL.md巨长Agent加载后占用大量上下文窗口反而没空间去看代码了。现在我的原则是SKILL.md控制在两百行以内领域知识放到脚本或参考资料里需要的时候再按需读取。这就像你给新员工发手册手册目录写清楚就行别把整本手册背下来。第二个坑是规则误伤业务特例。比如有些项目会把日志加密密钥放在配置文件里扫描器看到“key ...”就报警但人家这是有意的设计。应对方法是在audit_rules.json里支持“白名单模式”允许项目声明哪些路径、哪些变量名是已知可接受的扫描时直接跳过。这能显著减少团队对AI审计的“狼来了”疲劳。第三个坑也是最玄学的就是Agent模型的版本差异。同一个Skill在不同模型版本下表现波动很大有时候突然像换了一个人规则执行得七零八落。我能给的建议是把SKILL.md里的关键指令写得更“笨”一些比如“遇到关键字的文件必须逐个列出文件名和行号不得只写文件名”这种傻瓜式指令在任何模型下都不容易被忽略。另外重要的审计结论一定要有脚本输出的结构化数据作为支撑不能只靠模型“觉得有问题”。最后一个建议别指望Skill是银弹。它能把安全审计的覆盖面扩大、让普通开发者也能获得接近专业审计师的初筛能力但替换不了专业安全人员对复杂业务风险的设计判断。我现在的用法是“AI做初筛人做复核”两者组合安全效率提升明显风险也控得住。如果你也在搭自己的Agent工作流建议不要把Skill定义成“检查者”而是定义成“辅助你思考的搭档”那才是它真正发光的地方。
觉得有用,分享给同行:

为您的企业打造数字门面

稳重轻奢商务风格,端正雅致视觉,长效耐看不易过时。

立即咨询 →