最近用 AI 编程工具做项目,代码产出速度是上来了,但心里总悬着一件事:这代码到底安不安全?以前写代码,安全意识靠个人经验和 review 习惯撑着,现在换成 AI 批量生成,风险点也跟着成倍增加。于是我把安全审计这套方法论,封装成了一个security-audit-skill技能包,专门给 codex、opencode 这类 agent 工具用。这篇文章就把整个 skill 的设计思路、SKILL.md 的写法、安装调用流程和踩坑记录完整拆给你。
1. 这个 skill 到底解决什么问题
先说说我为什么会盯上"安全审计技能化"这件事。我最近的工作流里,copilot、codex、claude code 这类工具已经从"写个函数"进化到"给一个需求能直接改完一个模块"。但问题也来了——AI 生成的代码里,经常出现一些看着合理、实则带洞的写法:
- 直接把用户输入拼进 SQL 查询,完全没有参数化。
- 前端把后端接口路径写死,权限校验裸奔。
- 日志里打印完整 token、密钥或者用户身份证号。
- 文件上传功能没有校验文件类型,随手就能传一个
.jsp或者.html上去。 - 依赖包版本直接写
latest,供应链攻击一打一个准。
你让 AI 检查这些,它当然能说出"存在 SQL 注入风险"这种话,但如果不给它一套标准化的审查流程,它的检查往往是随机的、零散的、想到哪儿查到哪儿。你让它"检查一下安全问题",它可能只扫了一遍输入校验就交差。
所以我的核心思路是:把安全审计从"临时起意的提问"变成"可复用的标准流程"。这就是 skill 机制的用武之地——它不是一个 prompt 模板,而是一整套带触发条件、执行步骤、检查清单、输出格式的技能包,agent 一旦命中场景,就会按着预设的方法论走完整个审计流程。
顺便说下 skill 和 agent 的区别。之前社区里争论挺多,我的理解是这样的:
| 维度 | Skill | Agent |
|---|---|---|
| 本质 | 一套带说明文档的方法论/流程包 | 一个目标驱动的自主执行体 |
| 回答的问题 | "怎么做" | "做什么、用什么做" |
| 复用性 | 高,多个项目可复用 | 中,带有状态和上下文 |
| 依赖 | 依赖宿主(codex/opencode)加载解释 | 自身具备规划、记忆、工具调用能力 |
| 组合方式 | 多个 skill 可被同一个 agent 调用 | 一个 agent 可调度多个 skill |
你可以把 skill 想成是菜谱,把 agent 想成是厨师。厨师知道今天要做一桌菜(目标),但他需要翻开菜谱才知道每道菜的具体步骤、火候和调料配比。security-audit-skill就是一本专门写给 AI 看的"安全审计菜谱"。
这个 skill 适合谁?三类人:
- 像我一样重度使用 AI 编程工具,但不想让代码质量失守的开发者。
- 安全工程师,想把自己的检查清单沉淀成团队可复用的资产。
- 团队 leader,想在 codex/opencode 的 AI 编码流程里强制插入一个安全卡点。
说白了,这东西解决的核心痛点就是:AI 写代码可以快,但安全底线不能放。而靠口头嘱咐"你注意安全"是没用的,你得给 AI 一套它看得懂、能执行、可验证的标准化方法论。
2. security-audit skill 的整体设计与思路拆解
2.1 为什么选"流程化检查清单"而不是"自由问答"
一开始我也偷懒,直接在 codex 里跟它说"帮我审计一下这段代码"。它的表现是——确实找到了几个问题,但深度完全看心情。有时候它只找到 SQL 注入,忽略了硬编码密钥;有时候它把风格问题也当成安全问题列出来,报告里一堆噪音。
问题出在哪儿?缺少约束。大模型本质上是"最概率化的续写器",你给它一个模糊指令,它就会基于自己的训练分布给你一个"最像样但未必完整"的回答。而安全审计恰恰是一个不能靠猜的领域——你漏掉一个检查项,可能就等于把一个高危漏洞放进了生产环境。
于是我把审计流程拆成了标准阶段:
- 信息收集:让 AI 先确认审计范围、技术栈、框架版本、数据流入口。
- 威胁建模:基于 STRIDE 模型,枚举这个系统最可能被攻击的入口。
- 逐项代码扫描:按检查项清单逐条对照,而不是指望 AI 自己想起来。
- 漏洞评估与报告:按 CVSS 口径评估危害等级,输出可执行的修复建议。
关键在第三步——检查项清单。我参考了 OWASP Top 10 2021、CWE Top 25 2023、SEI CERT 安全编码标准,把它们压缩成适合 LLM 执行的粒度。比如"输入验证"这条,我会拆成:
- 用户输入是否经过白名单校验?
- SQL 查询是否使用参数化或 ORM 占位符?
- 输出到 HTML 的内容是否经过编码?
- 文件路径是否做了归一化,能否通过
../绕过? - 上传文件是否校验了 MIME 类型、扩展名、文件头魔数?
为什么拆这么细?因为大模型非常擅长"对照检查",但不擅长"主动发现"。你给它 20 条明确规则,它一条一条过,覆盖率高;你让它自由发挥,它大概率只给到你训练语料里最常出现的 3-4 个漏洞类型,比如 SQL 注入和 XSS,然后就停了。
2.2 SKILL.md 的元信息设计:让 agent 正确识别和触发
skill 的核心文件是SKILL.md,它靠 frontmatter(YAML 头)告诉 agent 自己是什么。这里有几个字段我反复调过,直接说结论:
--- name: security-audit-skill description: 对代码库进行系统化安全审计,覆盖 OWASP Top 10、CWE Top 25、敏感信息泄露、依赖漏洞等场景。当用户要求检查代码安全、执行安全审计、评估漏洞风险时使用。 version: 1.2.0 metadata: author: your-name tags: [security, audit, code-review, owasp, cwe, vulnerability] trigger: 安全审计, 代码安全, 漏洞检查, security audit, vulnerability scan ---这里最值得琢磨的是description字段。在 codex 和 opencode 的实现里,agent 是通过读 description 来决定要不要加载这个 skill 的。如果 description 写得太宽泛(比如"处理安全问题"),它什么场景都触发,反而变成干扰;如果写得太窄(比如"审计 Python 代码"),遇到 Java 项目它就不加载了。
我的经验是:description 里写"触发条件"比写"功能定义"更有效。我踩过坑:第一版 description 写的是"Provide comprehensive security auditing capabilities",结果 codex 经常在用户聊安全话题时误触发,但在真正需要审查代码时反而没触发。改成"当用户要求检查代码安全、执行安全审计、评估漏洞风险时使用"之后,命中率明显提升——因为它是在描述一个"场景",而不是描述一个"对象"。
另外,触发词的写法也建议多语言、多别名。比如"敏感信息泄露"这个词,代码库里可能有不同的叫法:硬编码密钥、credentials 泄漏、token 暴露、secret 检测。我直接在 trigger 字段里把常见的说法全部列进去了。实测下来,这样做的效果是——你不需要记得 skill 的确切名字,只要用日常语言说"帮我查一下有没有把密码写死在代码里",agent 就能唤起这个技能。
2.3 为 AI 定制检查清单:粒度与可执行性
标准的安全审计清单(比如 OWASP ASVS)有一两百条,密密麻麻。你不能直接丢给 AI——它的上下文窗口有限,而且检查项太细太多的时候,模型会出现注意力稀释现象,就是把精力花在最前面几条上,后面的检查项草草略过。
所以,我做的第一件事是"汇总降维"。把 ASVS 里的需求合并成适合 LLM 逐条判断的检查问题。例如:
| 安全域 | 检查问题 | 对应 CWE/OWASP |
|---|---|---|
| 注入 | 所有 SQL 查询是否使用了参数化语句? | A03:2021-Injection, CWE-89 |
| 身份认证 | 会话 token 是否有过期时间?密码是否使用 bcrypt/argon2 等慢哈希? | A07:2021-Identif, CWE-798 |
| 敏感数据 | 代码中是否存在硬编码的密钥/AK/SK/密码? | A02:2021-Crypto Failures, CWE-321 |
| 访问控制 | 接口是否有鉴权中间件?对象级权限是否校验? | A01:2021-Broken Access Control, CWE-862 |
| 文件操作 | 文件上传是否校验类型/大小/内容?路径是否可穿越? | CWE-434, CWE-22 |
| 日志与监控 | 日志里是否打印了敏感字段?是否记录了必要的操作审计日志? | A09:2021-Security Logging, CWE-532 |
| 依赖安全 | 依赖版本是否固定?是否存在已知漏洞的高危版本? | A06:2021-Vulnerable Components, CWE-1104 |
每一条都用 Yes/No/Unknown 三态来标记,这样 AI 在回答时有明确的输出格式,不会含糊其辞。Unknown 这个状态很重要——AI 受限于上下文,有时候确实没法判断某个问题,这时候让它如实标记 Unknown,比它硬着头皮猜一个结果要好得多。
3. SKILL.md 的完整结构与关键写法
这节直接进入实操。我把我的SKILL.md完整结构拆出来,你可以直接照着改。
3.1 文件目录结构
skill 的目录组织方式和最终的分发、加载效率直接相关。我的目录长这样:
security-audit-skill/ ├── SKILL.md # 入口文件,agent 首先读取它 ├── skills/ │ ├── secret-scan.md # 敏感信息专项扫描 │ ├── dependency-audit.md # 依赖漏洞审计 │ └── owasp-review.md # OWASP Top 10 逐项审核 └── references/ ├── report-template.md # 审计报告模板 └── checklist-full.md # 完整检查清单主SKILL.md不要太长,建议控制在 250 行以内——太长的话,agent 加载时需要占用大量上下文窗口,反而挤压了它分析代码的空间。核心方法论和检查清单放在主文件里,专项细节和参考材料放到子文件里,让 agent 按需去读。
这个"目录分层 + 按需加载"的设计,是从真实使用中悟出来的。最初我把所有检查项全写在SKILL.md里,结果每次触发都要吃掉好几千 token,代码分析的空间被压缩到很小,审计深度直线下降。后来改成主文件负责"流程引导",子文件负责"专项细节",整体审计质量反而上来了。
3.2 流程引导部分怎么写
主SKILL.md里最核心的一段是"执行流程"。我一字一句地打磨过,目标是让 AI 拿到就能走:
## 执行流程 执行安全审计时严格遵循以下步骤: ### 阶段 1:确认审计范围 1. 询问/识别被审计项目的语言、框架、依赖管理工具。 2. 明确审计目标(如:发布前安全检查 / 历史代码风险排查)。 3. 输出审计范围界定,列出待检查目录和文件。 4. 若用户未提供范围,默认扫描当前工作区内的全部源代码文件。 ### 阶段 2:威胁建模 1. 识别应用入口点:用户输入、API 接口、文件上传、第三方回调。 2. 识别信任边界:哪些数据来自不可信来源,需要在哪里做校验。 3. 基于 STRIDE 列出潜在威胁,输出威胁列表与优先级。 ### 阶段 3:逐项代码扫描 1. 读取完整检查清单(skill 子文件或主文件附录)。 2. 按检查项逐个审查代码,每个检查项输出: - STATUS: PASS / FAIL / UNKNOWN - 涉及文件 - 问题描述 - 建议修复方案 3. 不要合并或跳过检查项。遇到无法判断的项标记 UNKNOWN,不要猜测。 ### 阶段 4:输出审计报告 严格使用以下格式输出: 1. 摘要(漏洞总数、高危/中危/低危数量) 2. 漏洞列表(按严重程度排序) 3. 每个漏洞的详细说明(复现路径、影响、修复建议) 4. 审计范围与未覆盖项说明这里有个细节值得展开:**"不要合并或跳过检查项"这句话,加上"无法判断的项标记 UNKNOWN,不要猜测"**这条约束,是非常关键的。我在没有加这句话前,AI 经常自作聪明地跳过高危项检查,理由是"该框架默认安全"或者"该语言类型安全不易注入"。加了之后,AI 会老老实实把每一步走完。
为什么会这样?因为大模型有一个倾向:为了输出看起来"完整确定"的报告,它会把不确定的东西顺理成章地合理化。你明确告诉它可以输出 Unknown,反而给了它诚实的空间,减少幻觉。
3.3 案例库与评分机制
skill 里必须带案例。光有检查清单还不够,AI 需要知道"什么样的问题报告才算合格"。我在SKILL.md里放了两类案例:
高危案例示例:硬编码密钥
# 错误示例 AWS_ACCESS_KEY = "AKIAIOSFODNN7EXAMPLE" aws_client = boto3.client( "s3", aws_access_key_id=AWS_ACCESS_KEY, aws_secret_access_key="wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY", ) # 正确做法 # 通过环境变量注入,使用 secrets manager 或环境变量读取。 import os aws_client = boto3.client( "s3", aws_access_key_id=os.getenv("AWS_ACCESS_KEY_ID"), aws_secret_access_key=os.getenv("AWS_SECRET_ACCESS_KEY"), )# 发现硬编码密钥时的报告格式示例 - id: SEC-001 严重程度: 高危 类型: 敏感信息泄露 文件: src/config/aws.py:3 描述: 代码中硬编码了 AWS AK/SK,攻击者可通过版本库历史或源码泄露获取云资源访问权限。 复现路径: 读取文件第 3-4 行即可获得凭证。 修复建议: 改用环境变量注入,轮换已泄露的密钥,并从 Git 历史中清理敏感信息。评分机制——我给漏洞定了一个轻量分级:
- 严重(Critical):可直接被远程利用,如 RCE、SQL 注入、硬编码云凭证。
- 高危(High):需要一定条件但很容易触达,如存储型 XSS、越权访问。
- 中危(Medium):信息泄露、缺少安全头、日志泄露敏感信息。
- 低危(Low):代码风格、缺少注释、潜在性能问题(非安全问题不列入)。
为什么 AI 需要这个分级?因为它默认会"夸大严重性"。你让它"列出所有安全问题",它能给你整出 50 条,其中一半是风格问题。有了严重级别框架后,它输出报告时会自动按照这个口径去套,过滤噪音的能力强了很多。
我在测试中发现一个规律:在 SKILL.md 里写"非安全问题不要列入",远远比一句清单指令管用。因为后者只是约束了一次对话,前者则是在修改 AI 的"输出习惯"。这就是 skill 比 prompt 模板更强的地方——它带记忆,带默认值,带行为规范。
4. 安装到 codex / opencode / claude code 的实操全过程
4.1 codex 的 skill 安装
OpenAI Codex 目前支持通过~/.codex/skills/目录加载本地 skill。操作步骤如下:
# 1. 创建技能目录 mkdir -p ~/.codex/skills/security-audit # 2. 进入项目目录并拉取或创建技能文件 cd ~/.codex/skills/security-audit # 如果你的 skill 在 git 仓库中,直接 clone git clone https://your-repo/security-audit-skill.git . # 或者手动创建 SKILL.md touch SKILL.md如果你是自己从零搭建,最省事的做法是:
mkdir -p ~/.codex/skills/security-audit cat > ~/.codex/skills/security-audit/SKILL.md << 'EOF' --- name: security-audit-skill description: 检查代码安全、执行安全审计、评估漏洞风险时使用。 ... EOF装完之后怎么验证呢?直接在 codex 对话中输入:
请用 security-audit-skill 审查当前项目的 src/ 目录如果 skill 加载成功,codex 会先输出"审计范围"之类的阶段信息,然后按步骤执行。如果没有反应,检查一下你的版本是否支持 skill 机制——codex 的 skill 支持是从某个版本开始逐步开放的,太老的版本不会读取这个目录。
4.2 opencode 的 skill 安装
opencode 的 skill 机制类似,但目录放在~/.config/opencode/skill/下。安装命令:
mkdir -p ~/.config/opencode/skill/security-audit cp -r /path/to/security-audit-skill/. ~/.config/opencode/skill/security-audit/opencode 对 skill 的加载逻辑也是靠SKILL.md里的name和description来匹配。有一点和 codex 不同——opencode 对 description 的匹配更"敏感",只要描述里有相关词它就可能触发。这既是优势也是麻烦:如果你的 description 里同时提到了"安全审计"和"漏洞",那用户聊到"系统漏洞"时也可能触发审计流程,需要你在 description 里再加上"只处理代码层面的安全审查"这个限定。
4.3 claude code 与跨工具兼容
现在社区里最常用的是 claude code,它也用SKILL.md并用 frontmatter 定义,默认目录在~/.claude/skills/。所以同一套security-audit-skill可以直接拷贝过去用:
mkdir -p ~/.claude/skills/security-audit cp -r /path/to/security-audit-skill/. ~/.claude/skills/security-audit/这里有个经验:尽量用相对路径和通用的 markdown 语法写 SKILL.md,不要混入某个工具特有的指令语法。我见过有人把 codex 专属的一些指令写进 skill,结果拿到 claude code 里完全不认。凡是 agent 无关的部分(检查清单、报告模板、威胁建模方法论)都保持组织无关性,然后把工具相关的部分留在调用层处理。
除了本地目录,还可以通过项目的AGENTS.md或仓库 config 来引用远程 skill。例如在.opencode/config.json里配置外部 skill 源,或者在AGENTS.md中写明"项目安全审计使用 security-audit-skill"。这种方式适合团队统一管理,把 skill 单独放一个仓库,任何成员 clone 项目后自动生效。
4.4 触发方式的调优
skill 装好之后,最大的变数是"触发"这个环节。我实测下来,自然语言触发比命令触发要可靠得多。比如你说:
- "帮我检查一下这段代码有没有 SQL 注入" ✅
- "运行安全审计流程" ✅
- "审计" ✅
这三类都能触发。但是如果你只说:
- "代码质量怎么样?" ❌(可能触发 code review skill 而非 security-audit)
这一点在描述里就写了触发条件,但实际用下来还得掌握说话的艺术。我的建议是:在代码 review 的流程里,如果你同时挂了多个 skill(比如一个 code-review-skill、一个 security-audit-skill),请务必在需求描述里说清楚是"安全审计"还是"代码风格审查"。因为你只说"帮我看看这段代码",agent 会随机选择一个它认为最能匹配的 skill,而你没法控制它选哪个。
另外一个调优技巧:如果你发现某个工具对你定的触发词不敏感,可以在对话中主动点名:
使用 security-audit-skill 审查 app/controllers/ 下的所有 controller 文件点名之后,大部分工具都会强制装载对应的 skill。这也是最保险的调用方式,尤其适合做 CI 流水线时的自动化调用。
5. 实战案例:用 security-audit-skill 审计一个 Flask 项目
光说不练假把式。我拿一个测试用的 Flask 项目跑了完整流程,把关键的输出和调优过程贴出来。
5.1 审计对象与启动
项目是个简单的博客系统,用 Flask + SQLite 实现,包含用户注册登录、文章发布、上传头像这几个功能。我对 codex 输入:
security-audit-skill 审计当前项目,重点检查用户输入处理和权限校验codex 加载 skill 后,第一步先确认审计范围:
审计范围确认: - 语言: Python 3.10 - 框架: Flask 2.2 - 数据库: SQLite 内置 sqlite3 - 待检查目录: /project/src/ - 重点: 用户输入处理、权限校验、认证逻辑我看到这一步时很欣慰——以前没有 skill 的时候,AI 从来不会先确认范围,基本拿起来就看。范围确认的好处是,AI 能主动感知技术栈,然后在后面检查的时候,给出适配框架的修复建议,而不是空泛地说"请使用参数化查询"。
5.2 发现的问题示例
审计过程中输出的几个典型问题,我挑代表性的放出来:
问题 1:SQL 注入(高危)
# 原始代码 def get_article(article_id): conn = sqlite3.connect("blog.db") cursor = conn.execute( f"SELECT * FROM articles WHERE id = {article_id}" ) return cursor.fetchone()skill 输出:
- id: SEC-001 严重程度: 高危 类型: SQL 注入 文件: src/db.py:18 描述: 文章 ID 直接拼接进 SQL 查询。若 article_id 来自用户请求参数, 攻击者可构造恶意值实现数据越权、SQL 注入。 复现路径: 请求 /article?id=1 OR 1=1 修复建议: 使用参数化查询: cursor.execute("SELECT * FROM articles WHERE id = ?", (article_id,))这里 skill 给的修复建议是带代码的,而且是针对 SQLite 的?占位符——匹配了项目的实际技术栈。以前没 skill 时,AI 给的修复建议经常是"建议使用 ORM 框架",等于没说。
问题 2:文件上传无类型校验(高危)
# 原始代码 @app.route("/upload", methods=["POST"]) def upload(): file = request.files["avatar"] file.save(os.path.join("uploads", file.filename))- id: SEC-003 严重程度: 高危 类型: 文件上传漏洞 文件: src/routes.py:45 描述: 未校验上传文件类型与内容,且文件名直接使用用户提供的原始文件名, 可上传恶意脚本并导致路径穿越或 XSS。 复现路径: 上传 avatar.html 并访问 /uploads/avatar.html 修复建议: 1. 使用 werkzeug.utils.secure_filename 处理文件名。 2. 校验 Content-Type 和文件扩展名白名单。 3. 将上传目录放在静态目录外,用独立路由读取。问题 3:日志记录敏感信息(中危)
- id: SEC-007 严重程度: 中危 类型: 敏感信息泄露 文件: src/utils/logger.py:12 描述: 登录失败时记录了完整的用户名与密码字段。 修复建议: 日志中移除 request.form 的完整输出,仅记录用户名字段用于审计。整个审计过程跑完,codex 输出了一份包含 9 个问题的报告,其中高危 2 个、中危 3 个、低危 4 个。对比没有挂 skill 时,它通常只能发现 2-3 个问题且报告格式混乱。差距肉眼可见。
5.3 审计报告的数据结构
为了让报告能直接被后续工具消费,我在 SKILL.md 里让 AI 同时输出一份 JSON 版本:
{ "summary": { "total": 9, "critical": 0, "high": 2, "medium": 3, "low": 4 }, "vulnerabilities": [ { "id": "SEC-001", "severity": "high", "type": "sql-injection", "file": "src/db.py", "line": 18, "fix": "use parameterized query", "status": "open" } ] }这个 JSON 格式非常适合 CI 流程——你可以把它接入 GitLab CI 的 security report 里,也可以扔给后续的修复 agent 去自动改代码。我目前的路子是:审计完拿到 JSON,再喂给另一个 fix agent 让它对照修复建议改代码,改完再跑一轮 security-audit 验证。
6. 常见问题与排查技巧实录
6.1 skill 不触发,或者触发了但没按流程走
这是最常碰到的问题。我踩过的坑和解决思路:
| 症状 | 可能原因 | 排查方案 |
|---|---|---|
| 输入触发词后完全没有反应 | skill 目录路径不对 | 检查~/.codex/skills/或~/.config/opencode/skill/目录结构,确认 SKILL.md 在正确的子目录下 |
| 触发了,但没按 SKILL.md 执行 | description 里没有把"必须按流程执行"写明确 | 在 SKILL.md 开头加一句"本技能必须严格按以下流程执行,不得跳过任何阶段" |
| 检查项被跳过 | 清单太长,上下文溢出 | 把检查清单拆到子文件,用"读取 skill 子文件 xx.md 后继续"让它按需加载 |
| 报告格式混乱 | 没有强约束输出格式 | 在 SKILL.md 里给出一个明确的报告模板和示例,并写明"必须严格按此模板输出" |
其中第一个问题最隐蔽。我看过很多社区帖子说"skill 装不上",最后发现是目录层级不对。以 codex 为例,~/.codex/skills/security-audit/SKILL.md是正确路径,但如果你多套了一层变成~/.codex/skills/security-audit/security-audit-skill/SKILL.md,它有时候也能识别,有时候不行——取决于具体版本的实现。我的建议是:宁可平铺也不要嵌套。
6.2 如何让 AI 的审计结果更"深"
第二个常见问题是:AI 能发现明显的安全问题,但深层次的逻辑漏洞(比如竞态条件、业务逻辑越权)它发现不了。这跟模型能力有关,但也跟 skill 设计有关。
我做过几次优化,效果比较明显:
在流程里加入"威胁建模"阶段。让 AI 先画出数据流,想想谁是攻击者、攻击面在哪,再开始检查代码。加了这步之后,AI 在一些"非典型"漏洞上的发现率明显提升,因为它不是机械扫清单,而是带着攻击者思维读代码。
明确要求 AI 读取完整文件,而不是只读片段。有时候 AI 只看了一个函数的 10 行代码就开始评论。我在 SKILL.md 里写了一条规则:"分析文件时,先读取整个文件再输出结论;如果文件太长,分模块读取并交叉引用。"这条倒是很管用,减少了大量误报。
让 AI 输出"为什么这个是安全的"。我让 AI 对每个关键安全域(认证、授权、输入校验)都给出"防护依据",把它认为安全的原因说明白。当它没法说清楚时,它会自动转回"unknown"状态并继续深挖。这个技巧叫"迫使模型暴露不确定性",实测能减少幻觉式审计结果。
6.3 多语言项目的 skill 适配
我审计过一个 Java Spring Boot 项目,一开始直接用通用 skill,结果 AI 给出的修复建议是 Python 风格的,比如"使用 Django ORM"。这就是没有在 skill 里做技术栈适配的结果。
后来我在 skill 的"阶段 1:确认审计范围"里增加了"技术栈适配"环节:
确认技术栈后,针对不同语言输出对应的安全要点: - Java/Spring: 检查 @RequestParam 参数绑定、SpEL 注入、Fastjson 反序列化、Spring Security 配置。 - Python/Flask/Django: 检查 SQL 拼接、模板渲染 XSS、文件上传、pickle 反序列化。 - Node.js/Express: 检查原型链污染、命令注入、SSRF、JWT 验签逻辑。 - Go: 检查 error 处理、sqlx 拼接、并发竞争、template.HTML 使用。这样 AI 在启动阶段就会锁定技术栈,后面的检查会更精准。如果你的项目是 TS 全栈,我建议你直接在 skill 里加一个frameworks/ts-web.md之类的子文件,把 React/Next.js 的安全事项(比如 dangerouslySetInnerHTML、SSR props 泄漏)都列进去。
7. 这个 skill 还能怎么扩展
最后聊几个我目前在试的扩展方向,算是给已经搭好 security-audit-skill 的朋友一些后续思路。
方向一:和供应链安全结合。目前 skill 只用代码静态扫描,不支持实际执行npm audit或pip-audit命令。但我在 skill 里预留了dependency-audit.md子文件,里面写了让 AI 生成依赖审计命令并解析输出结果的流程。实测在带工具调用的 agent 环境里,它真能自己跑命令然后分析输出。这个方向我还在打磨,核心难点是如何让 AI 解析大量依赖告警并去重。
方向二:做成 CI 流水线的自动卡点。现在各家 agent 工具都有 CLI 模式,意味着你完全可以把"调用 agent + 加载 security-audit-skill"写进 CI。我目前的尝试是:在 GitLab CI 里加一个 stage,跑codex exec --skill security-audit-skill "审计本次 MR 变更代码",然后拿输出 JSON 判断是否阻断合并。这个玩法潜力很大,但还需要解决执行时间和误报控制的问题。
方向三:把审计结果反向喂给修复 agent。理论上你可以让一个 agent 跑审计,把 JSON 报告传给另一个 agent 执行修复,修完再跑一轮审计,形成一个闭环。我现在就是这么用的——两个 codex 实例,一个当检查员(security-audit-skill),一个当修理工(auto-fix-skill),中间用 JSON 交接。效果还行,但直接让同一个 agent 边审计边修复效果更好,因为修复的时候它还记得上下文。
方向四:把安全编码规范变成生成侧约束。现在这个 skill 是"事后审计",但你完全可以再做一个secure-coding-skill,在 AI 第一次写代码时就带上安全约束,比如"所有数据库访问必须用参数化查询""密钥必须从环境变量读取"等。我理想的流程是:先生成(用 secure-coding-skill 约束),再审计(用 security-audit-skill 验证),双保险。
我个人的体会是,skill 这种机制最大的价值不在于省了你写 prompt 的时间,而在于它让 AI 的行为变得可预期、可复用、可传承。你把一套安全审计方法论写进 SKILL.md,不仅今天的会话能用,明天的项目能用,全团队都能用,而且每个人拿到的都是同一套标准——这对安全这种"不能有死角"的领域来说太重要了。如果你也在用 AI 写代码,我强烈建议别只盯着生成速度,花一个下午把这类审计技能包搭起来,后面省下的是无数个半夜被线上漏洞叫醒的觉。