security-audit-skill 实战:给编码助手装上安全雷达

发布时间:2026/10/18 20:25:03
security-audit-skill 实战:给编码助手装上安全雷达
1. 从零拆解 security-audit-skill一个给编码助手装上安全雷达的实战项目第一次看到security-audit-skill这个项目名我的直觉是这大概率是给某个 coding agent 框架写的一个技能插件专门用来做代码安全审计。后来翻了一圈资料确认了判断——它本质上是一个可挂载到编码助手上的安全审计能力模块让 AI 在写代码、改代码、审代码的过程中顺手把安全漏洞也扫一遍。这件事的价值在哪儿你想想现在用 coding agent 写代码的人越来越多但绝大多数 agent 的默认行为是“能跑就行”。它不会主动告诉你这段 SQL 拼接有注入风险、这个接口没做鉴权、这个依赖版本有已知 CVE。security-audit-skill要解决的就是这个断层——把安全审计从“事后专门找人做”变成“编码过程中自动触发”。这篇文章适合三类人看一是正在给自研 coding agent 扩展能力的开发者二是想了解 AI 辅助安全审计怎么落地的一线工程师三是团队里负责代码质量、想把安全左移做到位的技术负责人。我会从设计思路、核心机制、实操接入、问题排查几个维度把这个项目拆透尽量让你看完就能动手复现。2. 为什么要在 coding agent 里塞一个安全审计技能2.1 传统安全审计的痛点在哪做过代码审计的人都知道传统模式基本是这么走的开发写完代码 → 提交 PR → 安全团队或资深工程师人工 review → 发现问题打回 → 开发修改 → 再 review。这个流程有两个致命问题。第一是滞后。漏洞在代码写完几天甚至几周后才被发现这时候开发脑子里早就不记得当时的上下文了修起来成本极高。第二是覆盖不全。人工 review 受限于精力和经验一个几百行的 PR 能认真看完就不错了更别说跨文件追踪数据流。我见过太多团队的安全 review 最后变成“看看有没有硬编码密码”这种表面功夫。还有一个隐性成本安全团队和开发团队之间的沟通摩擦。安全说“这里有注入”开发说“这是内部接口不存在注入”来回扯皮。根因是审计发生在编码之后双方不在同一个上下文里。2.2 coding agent 天然适合承载安全审计coding agent 和传统静态扫描工具最大的区别是它有上下文。它知道你正在写什么功能、这个函数的调用方是谁、数据从哪来要到哪去。传统 SAST 工具只能做模式匹配看到execute(就报误报率高得吓人。而 agent 可以结合语义判断这个参数是不是用户可控的有没有经过校验security-audit-skill的设计思路就是利用这一点。它不是独立跑一个扫描器而是作为 agent 的一个“技能”存在。当 agent 在写代码或读代码时这个技能被触发agent 用自己已经掌握的上下文去做安全判断。这比冷启动的扫描器精准得多。另外agent 可以在生成代码的同时做审计。比如你让它写一个用户查询接口它在生成 SQL 语句的那一刻就能意识到“这里用了字符串拼接应该改成参数化查询”然后直接生成安全的版本。这是真正的安全左移——左移到代码还没写出来的时候。2.3 这个技能的核心能力边界需要说清楚的是security-audit-skill不是万能的。它擅长的是注入类漏洞SQL 注入、命令注入、模板注入、XSS鉴权与访问控制接口是否缺少权限校验、越权风险敏感信息处理硬编码密钥、日志泄露敏感数据、不安全的加密用法依赖与配置已知漏洞依赖、不安全的默认配置数据流追踪从用户输入到危险函数的完整路径它不擅长或做不好的复杂的业务逻辑漏洞需要理解业务规则竞态条件、时序攻击这类需要运行时分析的问题加密协议层面的深度缺陷理解这个边界很重要否则你会对它产生不切实际的期望然后在某个它没查出来的漏洞上翻车。3. security-audit-skill 的核心机制拆解3.1 技能是怎么挂载到 agent 上的从项目结构来看security-audit-skill遵循的是主流 coding agent 框架的 skill 规范。通常一个 skill 包含几个核心部分一个描述文件声明技能名称、触发条件、能力范围、一个或多个提示词模板告诉 agent 在不同场景下怎么执行审计、以及可选的辅助脚本或规则库。描述文件的作用是让 agent 知道“我什么时候该用这个技能”。比如当用户说“帮我 review 这段代码”或者 agent 自己检测到正在生成涉及数据库操作的代码时就触发安全审计流程。这个触发机制设计得好不好直接决定了技能是“有用”还是“烦人”。触发太频繁agent 每写一行都唠叨安全问题体验极差触发太少又起不到作用。我看到的实现里触发条件通常分两类显式触发用户主动要求安全审计和隐式触发agent 根据代码特征自动判断。隐式触发的规则一般包括检测到危险函数调用、检测到用户输入处理、检测到鉴权相关代码、检测到加密操作等。3.2 审计提示词的设计逻辑这是整个技能最核心的部分。安全审计的质量八成取决于提示词写得好不好。一个粗糙的提示词是“检查这段代码有没有安全问题”agent 大概率给你返回一堆泛泛而谈的东西。好的提示词需要做到几件事。第一给出明确的审计维度清单。不是让 agent 自由发挥而是告诉它按注入、鉴权、敏感信息、依赖、配置这几个维度逐一检查。每个维度下再给出具体的检查点。比如注入维度下要检查是否使用参数化查询、是否对用户输入做了转义、是否使用了安全的模板引擎。第二要求 agent 追踪数据流。光看一个函数是看不出问题的。提示词里要明确要求 agent 从入口点如 HTTP 请求参数开始追踪数据经过的每一个函数直到它被使用的地方。这条路径上任何一环缺少校验都是潜在漏洞。第三强制给出证据和修复建议。不能只说“这里有风险”要指出具体哪一行、为什么有风险、攻击者可能怎么利用、应该怎么改。这个要求会倒逼 agent 做更深入的分析而不是浅尝辄止。第四区分严重等级。不是所有问题都一样紧急。提示词里要定义清楚什么算高危可直接利用的注入、缺失的鉴权、什么算中危信息泄露、弱加密、什么算低危代码规范类。这样输出结果才有可操作性。3.3 规则库与知识注入纯靠提示词让 agent 判断安全问题覆盖面有限。security-audit-skill通常会配套一个规则库里面沉淀了常见漏洞模式、危险函数清单、安全编码规范等。这个规则库的作用是给 agent 提供“检查清单”避免遗漏。规则库的形态可以是多种多样的。简单的是 YAML 或 JSON 格式的规则列表每条规则包含规则 ID、描述、匹配模式、严重等级、修复建议。复杂一点的会包含数据流分析规则定义 source用户输入点和 sink危险操作点以及 sanitizer净化函数。我个人的经验是规则库不要贪多。一开始就堆几百条规则维护成本极高而且很多规则在特定技术栈下根本不适用。更好的做法是先覆盖团队技术栈里最常用的框架和最常见的漏洞类型跑通之后再逐步扩展。3.4 与 agent 主循环的集成方式技能和 agent 主循环的集成方式决定了审计是“顺手做”还是“专门做”。有两种模式。内联模式agent 在生成或修改代码的同一个回合里顺便执行安全审计。好处是上下文完全一致审计结果直接反馈到代码生成中可以立即修正。坏处是会增加单次响应的长度和耗时。分离模式agent 完成代码生成后单独触发一次审计流程。好处是审计可以更深入、更系统不受生成过程的干扰。坏处是上下文可能已经部分丢失而且需要额外的交互轮次。从实际效果看内联模式更适合“预防”分离模式更适合“检查”。成熟的实现通常会结合两者生成时做轻量级内联检查快速拦截明显问题生成后做一次完整的分离审计深度排查。4. 实操接入把安全审计技能跑起来4.1 环境准备与依赖确认在接入之前先确认你的 coding agent 框架支持 skill 扩展机制。目前主流的几个框架如 Claude Code、Cursor 的 agent 模式、开源的 Continue 等对 skill 的支持方式不太一样。你需要先搞清楚你的框架是加载本地 skill 目录还是通过配置文件注册还是通过 API 动态注入。以本地 skill 目录加载为例通常的目录结构是这样的skills/ security-audit-skill/ skill.yaml # 技能描述文件 prompts/ audit-full.md # 完整审计提示词 audit-inline.md # 内联快速检查提示词 rules/ injection.yaml # 注入类规则 auth.yaml # 鉴权类规则 secrets.yaml # 敏感信息规则 scripts/ scan_deps.py # 依赖扫描辅助脚本skill.yaml是入口里面声明技能名称、版本、触发条件、引用的提示词和规则文件。不同框架的 schema 有差异但核心字段大同小异。4.2 技能描述文件的编写要点描述文件写得好不好直接影响技能能不能被正确触发。以下是一个参考结构name: security-audit-skill version: 1.0.0 description: 对代码进行安全审计覆盖注入、鉴权、敏感信息、依赖等维度 triggers: explicit: - 安全审计 - security audit - 检查安全问题 implicit: - pattern: execute\\(|query\\(|raw\\( context: database - pattern: eval\\(|exec\\(|system\\( context: command - pattern: password|secret|token|api_key context: hardcoded prompts: full: prompts/audit-full.md inline: prompts/audit-inline.md rules: - rules/injection.yaml - rules/auth.yaml - rules/secrets.yaml这里的关键是implicit触发条件的设计。模式匹配要精准不能太宽泛。比如password这个词在变量名里出现太常见了如果只要出现就触发审计会非常吵。更好的做法是结合上下文判断比如检测到password xxx这种字面量赋值才触发。4.3 审计提示词的完整模板下面是我根据项目思路整理的一份完整审计提示词模板你可以直接拿去改你是一名资深应用安全工程师正在对以下代码进行安全审计。 ## 审计范围 - 文件{{file_path}} - 变更内容{{diff}} - 技术栈{{tech_stack}} ## 审计维度 请按以下维度逐一检查每个维度都要给出结论有问题/无问题/不适用 ### 1. 注入类 - SQL 注入是否使用参数化查询是否有字符串拼接 SQL - 命令注入是否调用了系统命令参数是否用户可控 - 模板注入模板渲染是否使用了用户输入作为模板内容 - XSS输出到前端的数据是否做了转义 ### 2. 鉴权与访问控制 - 每个接口是否有权限校验 - 是否存在越权访问风险水平/垂直 - 敏感操作是否有二次确认 ### 3. 敏感信息 - 是否有硬编码的密钥、密码、token - 日志中是否输出了敏感数据 - 加密算法是否安全禁用 MD5、SHA1 做密码哈希 ### 4. 依赖与配置 - 新增依赖是否有已知漏洞 - 配置项是否安全如 debug 模式、CORS 配置 ## 输出格式 对每个发现的问题按以下格式输出 - **严重等级**高危/中危/低危 - **位置**文件:行号 - **问题描述**具体是什么问题 - **攻击场景**攻击者可能如何利用 - **修复建议**具体的修改方案最好给出代码示例 如果没有发现问题明确说明未发现安全问题。这份提示词的核心是结构化。它不给 agent 自由发挥的空间而是逼着它按维度逐一检查。实测下来结构化提示词的漏报率比开放式提示词低很多。4.4 规则库的落地写法规则库用 YAML 写比较直观以下是一个注入类规则的示例rules: - id: SQL_INJECTION_001 name: 字符串拼接 SQL severity: high description: 检测到使用字符串拼接构造 SQL 语句 patterns: - execute\\(.*\\.*\\) - query\\(.*\\.*\\) - raw\\(.*\\.*\\) languages: - python - javascript - java fix: 使用参数化查询将用户输入作为参数传入而非拼接进 SQL 字符串 references: - CWE-89 - id: CMD_INJECTION_001 name: 命令注入 severity: high description: 检测到将用户输入传入系统命令执行函数 patterns: - os\\.system\\(.*\\) - subprocess\\.(call|run|Popen)\\(.*shellTrue.*\\) - exec\\(.*\\) languages: - python fix: 避免使用 shellTrue使用参数列表形式传参或对输入做严格白名单校验 references: - CWE-78规则库的维护是个长期活。我的建议是每次审计发现新类型的问题就把它沉淀成一条规则。这样规则库会随着项目使用越来越完善。4.5 依赖扫描脚本的接入依赖漏洞是很容易被忽略的一块。security-audit-skill通常会带一个辅助脚本用来扫描项目依赖的已知漏洞。Python 项目可以用pip-auditNode 项目可以用npm audit通用方案可以用osv-scanner。脚本的核心逻辑是读取依赖清单文件requirements.txt、package.json、go.mod 等调用漏洞数据库 API返回有问题的依赖列表。这个脚本的输出会被注入到审计提示词里作为依赖维度的检查依据。import subprocess import json def scan_dependencies(project_path): 扫描项目依赖的已知漏洞 result subprocess.run( [osv-scanner, --format, json, --recursive, project_path], capture_outputTrue, textTrue ) if result.returncode ! 0: return {error: result.stderr} return json.loads(result.stdout)这个脚本不需要多复杂关键是能跑通、能拿到结构化结果。拿到结果后在提示词里告诉 agent“以下是依赖扫描结果请结合这些信息评估依赖风险。”5. 审计效果验证与常见问题排查5.1 怎么验证审计技能真的有效技能接入之后不能光看它“有没有输出”要验证它“输出得对不对”。我通常用三种方式验证。第一种用已知漏洞的代码做回归测试。准备一批包含典型漏洞的代码样本SQL 注入、XSS、硬编码密钥等跑一遍审计看能不能全部检出。这个测试集要持续维护每次改提示词或规则库都跑一遍防止改出回归。第二种用干净代码测误报率。拿一批确认没有安全问题的代码跑审计看会不会报出一堆假阳性。误报率太高的话开发很快就会忽略审计结果技能就废了。第三种对比人工审计结果。找几段真实项目代码先让资深工程师人工审计一遍记录发现的问题再让技能审计一遍对比两者的差异。技能漏掉的问题分析原因并补充规则技能多报的问题分析是提示词太激进还是规则太宽泛。5.2 常见问题速查表问题现象可能原因排查方向解决方案技能完全不触发描述文件格式错误或路径不对检查 skill.yaml 语法和框架日志修正 YAML 缩进确认 skill 目录被正确加载触发太频繁干扰编码隐式触发条件太宽泛检查 implicit triggers 的模式匹配收窄匹配模式增加上下文条件审计结果泛泛而谈提示词不够结构化检查提示词是否有明确维度清单改用结构化提示词模板强制逐维度输出漏报明显漏洞规则库覆盖不足或提示词遗漏维度用已知漏洞样本测试定位漏报类型补充对应规则或在提示词中增加检查点误报率高规则模式太宽泛缺少上下文判断分析误报样本的共同特征增加白名单机制或要求 agent 追踪数据流后再下结论依赖扫描失败扫描工具未安装或版本不兼容手动执行扫描命令看报错安装对应工具确认版本检查网络访问审计耗时过长全量审计范围太大检查是否每次都对整个项目审计改为只审计变更部分diff全量审计定期执行5.3 几个我踩过的坑坑一提示词里没要求给行号。早期版本的提示词只说“指出问题位置”agent 经常只给个函数名开发得自己去找。后来强制要求输出文件:行号可操作性大幅提升。坑二规则库和提示词重复。一开始我在规则库里写了很多检查项提示词里又写了一遍结果 agent 收到重复指令输出变得混乱。后来明确分工规则库负责“模式匹配”提示词负责“语义分析”两者互补但不重复。坑三忽略了技术栈适配。通用规则在特定框架下可能完全不适用。比如在用了 ORM 的项目里execute方法可能已经被 ORM 封装成安全的了但规则还是会报。解决办法是在规则里加languages和frameworks字段做技术栈过滤。坑四审计结果没有优先级。一开始所有问题都平铺直叙地列出来开发不知道先修哪个。后来强制要求标注严重等级并且高危问题必须给出攻击场景开发一看就明白为什么要修。5.4 性能与体验的平衡安全审计技能最大的体验问题是“慢”和“吵”。慢是因为深度审计需要 agent 做大量推理吵是因为触发太频繁。针对慢的问题我的做法是分级审计内联检查只做快速模式匹配毫秒级完整审计在代码生成后单独触发秒级到十秒级。用户感知到的是“写代码时偶尔有提示写完代码后有一份完整报告”而不是“每写一行都卡一下”。针对吵的问题核心是只在真正有风险时出声。这需要不断调优触发条件和规则精度。我的经验是误报率控制在 10% 以下开发才愿意看审计结果超过 30%基本就被无视了。6. 进阶玩法让审计技能越用越聪明6.1 从审计结果反哺规则库每次审计发现的问题都是一条潜在的规则。我养成了一个习惯每周花半小时回顾本周的审计结果把新出现的漏洞模式沉淀成规则。这样规则库会随着项目使用自然生长而不是一开始就追求大而全。具体做法是审计报告里每个“高危”问题都问自己一句“这个模式能不能写成规则”。能写就写不能写就记录在案作为提示词优化的输入。6.2 结合项目历史做上下文增强同一个漏洞模式在不同项目里的风险等级可能完全不同。比如一个内部管理后台的 SQL 注入和一个面向公网的用户接口的 SQL 注入严重性差着量级。security-audit-skill可以通过读取项目配置如是否有公网入口、是否处理敏感数据来动态调整风险评级。这个增强需要 agent 能访问项目的元信息。实现方式可以是在提示词里注入项目上下文或者让 agent 主动读取项目里的配置文件。6.3 团队协作场景下的审计技能在团队里用这个技能有几个额外考虑。一是审计标准要统一不能每个人用自己的提示词版本。二是审计结果要能沉淀不能看完就丢。三是误报反馈要有渠道开发发现误报后能快速反馈规则维护者能快速修正。我的做法是把审计技能和代码审查流程绑定PR 创建时自动触发审计审计结果作为评论附在 PR 上。开发修复后重新触发直到没有高危问题才能合并。这样安全审计就成了流程的一部分而不是一个可有可无的附加项。6.4 持续演进的思路安全审计技能不是一次接入就完事的。攻击手法在变技术栈在变项目在变技能也得跟着变。我建议每季度做一次技能回顾看看这季度漏了哪些漏洞、误报了多少、规则库更新了多少条。用数据驱动技能的迭代而不是凭感觉。另外多关注安全社区披露的新漏洞模式及时把新的检查点加进提示词和规则库。比如近几年供应链攻击频发依赖审计的权重就应该相应提高。这个项目后续还可以往几个方向扩展一是支持更多语言和框架的规则二是引入数据流分析的自动化能力减少对 agent 推理的依赖三是和 CI/CD 流水线深度集成做到提交即审计、合并前拦截。不过这些都是后话先把基础能力跑通、跑稳再谈扩展。