最近AI编程助手圈子里的高频词就是“Skill”,几乎每天都能看到有人晒自己写的codex skill、claude skill、opencode skill。我在给自己的AI编码环境做安全能力的时候,也照着这套思路折腾了一个security-audit-skill,说白了就是把我平时做代码安全审计的那套检查方法,固化成一个AI能直接读、直接跑、直接出报告的技能包。一套流程跑下来,最大的感受是:安全审计这件事,特别适合做成Skill,因为它有固定的检查项、固定的流程、固定要输出的结果,比让对方“凭感觉帮我看看代码有没有问题”要靠谱太多。
这篇文章就把我搭建security-audit-skill的全过程拆开讲清楚,包括Skill到底是什么、一个审计型技能包该怎么设计目录结构、SKILL.md怎么写才不会被AI选择性忽略、代码/依赖/配置三类检查规则怎么固化、接入Codex、Claude Code这类工具后怎么跑通一次真实审计,以及我踩过的坑和排查方法。适合正在用AI编程助手、又对代码安全有要求的开发者,也适合团队里想给AI加一道安全底线的同学参考。
1. 先搞清楚:Skill是什么,为什么安全审计天生适合做成Skill
1.1 从“临时交代”到“技能包”:AI协作方式的转变
我先用大白话解释一下Skill到底是什么。以前我们让AI助手干一件专业的事,比如“审查一下这段代码有没有安全问题”,得在对话里临时塞上一大堆背景信息:项目用的什么框架、我们要关注哪些漏洞类型、报告按什么格式输出、哪些误报可以忽略。等换个新项目、新会话,又得重新交代一遍。这就好比你每次请一个临时工来干活,都要从头培训一遍,成本高,效果还不稳定。
Skill做的事情,就是把这一套“培训材料”打包成一个文件包,放在AI工具能识别的位置。AI加载技能包后,会主动按照里面的说明来执行任务。一个Skill通常包含一个主说明文件(一般是SKILL.md),里面写清楚触发条件、执行步骤、输出格式、行动边界,还可以带上规则文档、辅助脚本、参考资料。AI不是把Skill当普通对话内容来“参考参考”,而是把它当成“作业指导书”来执行。
这个变化的本质,是从“提示词”到“可复用工程资产”的升级。提示词是一次性的,换个会话就没了;Skill是持久化的,放进仓库里还能被团队共享、被版本管理,谁拉下来都能用。对安全审计这种高度流程化的活儿来说,这个特性太关键了。
1.2 security-audit-skill 到底负责哪些事
我给自己做的security-audit-skill,最初划定的职责范围是四块:源代码静态审计、依赖与供应链安全、敏感信息检测、配置与权限检查。
- 源代码静态审计:检查常见漏洞模式,比如注入、反序列化、危险函数调用、不安全的加密算法等。
- 依赖与供应链安全:检查依赖是否锁定版本、是否存在已知漏洞、lock文件是否缺失等。
- 敏感信息检测:扫描代码库里的API密钥、数据库口令、私钥等硬编码凭证。
- 配置与权限检查:查看云厂商配置、Docker配置、IAM权限声明,找出过度授权或暴露面过大的问题。
这里要特别说清楚边界。安全审计技能不等于渗透测试,也不等于漏洞利用。它是一道“体检”,负责发现问题、给出修复建议,但不负责“动刀”。我在SKILL.md里明确写了禁止行为:不主动调用攻击性工具、不尝试利用漏洞提权、不修改任何源代码文件,整个审计过程只读,所有修复动作都交给人工确认。这个边界既是合规要求,也是安全底线。AI自己执行攻击性操作的风险太大,任何人都应该把它锁死。
2. 动手前先搭框架:一个审计型技能包的目录结构
2.1 目录结构决定了AI能不能“按图索骥”
我最早写Skill时犯过一个典型错误:把所有检查和说明全部塞进一个巨大的SKILL.md文件里,结果AI加载后上下文被撑爆,好多规则根本没走到,输出还特别飘。后来参考社区里成熟的做法,把技能包拆成“主控文件 + 规则文件 + 脚本 + 参考材料”的结构。我目前稳定在用的目录长这样:
security-audit-skill/ ├── SKILL.md ├── rules/ │ ├── code-audit.md │ ├── dependency-audit.md │ ├── secret-audit.md │ └── config-audit.md ├── scripts/ │ ├── scan_secrets.py │ └── audit_deps.py ├── references/ │ ├── cwe-mapping.md │ └── owasp-top10-notes.md └── contexts/ └── project-context.md每个目录有明确的用途。SKILL.md是入口,负责“判断什么时候触发、按什么顺序做、最后输出什么”;rules目录放细分规则,AI在做某一类检查时按需读取,避免一次性读入太多内容;scripts目录放可执行脚本,凡是能用程序确定性判断的事情,优先让脚本做,而不是靠AI“猜”;references目录放参考资料,帮助AI理解漏洞背后的原理,提升报告的可解释性;contexts目录放项目相关的说明,比如项目技术栈、已知历史问题,相当于给审计员看的“项目背景”。
2.2 SKILL.md 怎么写才不会被AI“选择性忽略”
SKILL.md是整个技能包的灵魂,但也是最容易写废的文件。我复盘过很多次,发现AI对说明文件的执行程度,和编写方式高度相关。下面几条是我实测下来最影响执行效果的点。
第一,开头就要写清楚触发条件。我习惯写一个Triggers段落,告诉AI在什么情况下必须激活这个技能。比如“当用户提及安全审计、安全检查、security audit、扫描漏洞、检查依赖安全、检测密钥等关键词,或要求对项目进行安全审查时”。这相当于给AI装了一个启动开关。
第二,执行流程必须步骤化。不要写一堆描述性的段落,而是写明Step 1、Step 2、Step 3,每一步做什么、输出什么、读哪个文件。AI对步骤化的指令执行率远高于泛泛的说明。
第三,明确输出格式。我在SKILL.md里写死了报告模板:按严重级别分类、每条漏洞附上文件路径、行号、问题描述、修复建议。固定输出格式之后,报告的可读性大幅提升,也方便后续接入自动化流程。
第四,写清楚“不要做什么”。比如绝不执行破坏性命令、不修改源码、不把凭证打印到日志。AI在安全任务里容易“太主动”,给出一份行为红线非常必要。
第五,给足示例。在SKILL.md末尾放一个输入示例和对应的输出示例,AI会把这个当成格式参照。这个做法对输出质量的提升非常明显。
我当时第一版SKILL.md大概写了200多行,后来精简到100行左右,把大量细碎规则挪到了rules目录。主文件短而清晰,rule文件深而具体,这个配合比“一篇长文走天下”要可靠得多。
3. 核心内容:把安全审计经验固化成机器可读的规则
3.1 代码审计规则要怎么写才能抓到真问题
代码审计规则是整个技能包的重头戏。我一开始试图让AI自由发挥,结果它只能说出“存在SQL注入风险”这种空话,别说修复建议了,连具体位置都经常给错。后来我把检查规则逐条写成“模式 + 风险等级 + 说明 + 修复建议”的结构,效果才真正改善。
以Python项目为例,我固化了这样几类规则:危险函数检测(eval、exec、pickle.loads、yaml.load)、SQL拼接检测(f-string拼接SQL语句、format传参进入execute)、命令注入检测(os.system、subprocess调用时拼接外部输入)、硬编码密钥检测(正则匹配常见云厂商AK、私钥块、密码字段)。每条规则在code-audit.md里都写成下面这样:
## SQL注入:字符串拼接查询 - 风险等级: Critical - 检测模式: - 调用 cursor.execute / session.execute / engine.execute - 参数使用 f-string、format、% 拼接 - 说明: 直接拼接用户输入进SQL语句,可能导致注入。 - 修复建议: 使用参数化查询(? 占位符或命名参数),例如 execute("SELECT * FROM users WHERE id = ?", (uid,))这种规则的好处是,AI在执行时能对照模式去代码里找证据,而不是凭空抒情。而且规则文件本身也是团队知识库,新人一看就知道什么是重点。
3.2 依赖审计:别让AI自己猜,交给工具干确定性的事
依赖安全这块,我强烈建议让Skill调用现成的扫描工具,而不是让AI自己去“判断依赖有没有漏洞”。理由很简单:漏洞库是动态变化的,AI的知识截止时间决定了它根本不可能准确掌握最新CVE。让AI去猜等于拿旧地图找新路。
我的做法是在scripts/audit_deps.py里做两件事。第一件,检查项目有没有lock文件,比如requirements.txt、Pipfile.lock、poetry.lock、package-lock.json,没有就提示“依赖未锁定,存在供应链风险”。第二件,直接调用系统里安装的扫描器,比如pip-audit、osv-scanner、npm audit,把它们的输出捕获后整理成结构化结果,再交给AI汇总进最终报告。
这段逻辑本身不复杂,关键是把脚本的输入输出写清楚。AI不需要理解漏洞原理也能用这些结果,它只需要把脚本输出翻译成人类能看懂的报告。这正是“AI负责理解与表达,脚本负责确定性与准确性”的分工。
3.3 配置与权限审计:从配置文件里嗅出危险信号
配置审计是最容易被忽视、但实际事故率最高的部分。很多项目的代码本身写得挺干净,结果公网数据库端口开着、Docker以privileged方式跑、云厂商IAM给了“*”权限,一夜之间被打穿。所以我把配置审计单独做了一个规则文件。
规则覆盖几类场景:第一,云权限配置,检查IAM策略文本里有没有“Action”: “”或者“Resource”: “”这种过度授权写法;第二,数据存储暴露,检查配置文件里数据库地址是否绑定了0.0.0.0、公网RDS节点等;第三,容器安全,检查Dockerfile里有没有USER root、privileged: true、挂载了宿主机敏感目录比如/etc;第四,密钥管理,检查是否直接把明文口令写在配置文件里,而不是用环境变量或密钥管理服务。
这些规则几乎都是“静态看文本就能判断”的,非常适合固化成规则给AI执行。每次审计时,AI会读取配置文件、Dockerfile、部署清单,逐条对照规则,把命中项归档进报告。由于这类规则非常明确,误报率比代码审计低得多,整套技能里性价比最高的就是配置检查。
4. 实操记录:从零搭好Skill并跑通一次真实审计
4.1 初始化技能包并接入AI编程环境
下面是我实际操作的完整流程,照着做基本不会跑偏。
第一步,在本地建目录,这里我用的是一个专门存放技能的目录,然后初始化git仓库方便版本管理。
mkdir -p security-audit-skill/{rules,scripts,references,contexts} cd security-audit-skill git init第二步,编写SKILL.md,这是第一步的核心文件。我给了简化的开头示例,实际用的时候可以根据自己的项目补充细节。写完之后,把rules目录下的四个规则文件一一补齐。
第三步,把脚本放入scripts目录并赋予可执行权限。
chmod +x scripts/scan_secrets.py scripts/audit_deps.py第四步,把整个security-audit-skill目录放到AI工具能够识别的位置。不同的AI工具加载方式不一样,有的从全局skills目录加载,有的在项目根目录找.skill文件夹。我自己在Codex环境里会在项目根目录放一个.skill目录,在Claude Code环境里会把技能包路径加进配置。但总的原则是一样的:让AI明白它的工作目录里有一个可用的技能包,并且通过SKILL.md里面的触发词去激活它。
第五步,做一次最小验证。我通常会先对一个小仓库跑一遍,看AI会不会给出结构化的报告、会不会把规则真正执行出来。如果AI只是泛泛而谈,我就回头检查SKILL.md是否写得太模糊、规则是否没有被引用到。
4.2 演示一次完整的审计执行链路
我拿一个模拟的FastAPI小项目来演示。这个项目故意放了四个问题:一个SQL拼接、一个硬编码的API密钥、requirements.txt里没有锁版本、Dockerfile缺少非root用户。当我对AI说“用security-audit skill检查一下当前仓库”时,AI按SKILL.md里的流程依次执行。
第一步,AI列出项目文件清单并读取规则。第二步,AI调用scripts/scan_secrets.py扫描密钥和敏感信息,脚本输出命中位置。第三步,AI调用scripts/audit_deps.py检查依赖锁定情况,脚本提示requirements.txt缺少固定版本。第四步,AI读取Dockerfile和配置文件,对照config-audit.md做配置检查。第五步,汇总成报告。
脚本这块我简单展示一下scan_secrets.py的核心逻辑,正则扫描加上常见假阳性目录的排除:
#!/usr/bin/env python3 import re import os import sys KEY_PATTERNS = [ (re.compile(r'(?i)(api[_-]?key|secret|password|token)\s*[:=]\s*["\'][^"\']+["\']'), 'Potential credential assignment'), (re.compile(r'(AKIA[0-9A-Z]{16})'), 'AWS Access Key'), (re.compile(r'-----BEGIN (RSA |EC |DSA |OPENSSH )?PRIVATE KEY-----'), 'Private Key Block'), ] SKIP_DIRS = {'.git', 'node_modules', 'venv', 'dist', 'build', '__pycache__'} def scan(path): results = [] for root, dirs, files in os.walk(path): dirs[:] = [d for d in dirs if d not in SKIP_DIRS] for fname in files: fpath = os.path.join(root, fname) if os.path.getsize(fpath) > 2 * 1024 * 1024: continue try: content = open(fpath, 'r', encoding='utf-8', errors='ignore').read() except Exception: continue for pattern, desc in KEY_PATTERNS: for m in pattern.finditer(content): line_no = content[:m.start()].count('\n') + 1 results.append((fpath, line_no, desc)) return results if __name__ == '__main__': for file, line, desc in scan(sys.argv[1] if len(sys.argv) > 1 else '.'): print(f'{file}:{line}: [{desc}]')AI最后生成的大致报告如下:
[Critical] SQL注入风险 文件: app/db.py:42 描述: 使用f-string拼接用户输入构造SQL查询 建议: 改为参数化查询 [High] 硬编码API密钥 文件: app/config.py:17 描述: 检测到疑似API密钥赋值 建议: 改用环境变量或密钥管理服务 [Medium] 依赖未锁定版本 文件: requirements.txt 描述: 未发现版本锁定或lock文件 建议: 使用pip freeze生成requirements.lock [Medium] 容器以root用户运行 文件: Dockerfile 描述: 未声明非root用户 建议: 添加USER appuser并创建低权限用户这个报告格式就是我当初在SKILL.md里把输出模板写死之后得到的效果。没有这一步,AI的输出经常是一段散文,有了固定模板,结果稳定多了。
4.3 用了一段时间之后的实际感受
我拿这个技能包跑了几个中型项目,最直观的感受是:当规则定型之后,AI的审计覆盖率是很稳的,只要项目结构不是特别刁钻,像SQL注入、硬编码密钥、依赖未锁版本、容器没有非root用户这类高频问题,几乎一抓一个准。它做不到人类资深审计员的“灵光一现”,但对常规检查项的覆盖能力已经非常接近标配流程了。更重要的是,它可以作为第一道防线反复免费跑,人工只需要复检被命中的项和看看有没有漏网之鱼。
漏报情况也确实存在,尤其是那种需要跨文件理解业务逻辑才能发现的漏洞,AI很难靠规则命中。所以我的定位是“机器查常规,人查逻辑”,两者配合而不是互相替代。这个认知很重要,能避免对技能包产生不切实际的期望。
5. 常见问题与排查技巧实录
5.1 技能包没有被AI加载或触发
这是我被问得最多的情况。检查顺序一般是:确认SKILL.md文件名和内容格式没有问题;确认技能目录放在AI工具要求的加载路径下;确认触发词是否与对话输入匹配,比如说了“检查一下安全”但触发条件里只写了“security audit”,那AI很可能不会激活技能;最后,在部分工具里,新增技能后要重新加载或重启会话,否则AI读不到新文件。
还有一个小坑:如果技能目录被.gitignore忽略了,或者放在了没有权限的目录里,AI也会找不到。我至少遇到两次是因为目录没读权限导致技能静默失效,排查了好久才发现是权限问题。
5.2 审计结果太泛、没有细节
如果AI给的报告全是“建议增强代码安全性”这种空话,多半是规则文件没有真正被AI引用。我在SKILL.md每个执行步骤后面都明确写了一句“请读取rules/code-audit.md并逐条对照检查”,这样AI才会真正去加载规则。另一个原因可能是项目太大,AI只扫描了根目录几个文件就仓促收尾。我的解法是在SKILL.md步骤里加了范围限制,要求AI优先检查代码入口、数据处理函数、数据库访问层、认证授权模块,并在报告里列出覆盖的文件数。有了这个要求,AI的覆盖范围明显变全了。
5.3 误报率偏高怎么办
误报集中在两类:一是把正常的配置项识别成风险,比如把测试环境的密码字段当成生产密码;二是密钥扫描把样例、mock数据当成了真实密钥。我的处理方式是两条。第一,在规则里加白名单条件,比如测试文件、fixtures、mock目录直接跳过;第二,输出分级,Critical和High只放有确定性证据的风险,Medium和Info级别用于提示性和疑似问题。分级之后,真正需要人工紧急处理的噪音少了很多,报告也更能让人信服。
5.4 关于AI执行边界的一点提醒
最后这条不是技术问题,但比技术问题更重要。安全审计技能包在运行时会读取大量代码和配置,AI环境必须是可信的,不要随意把包含生产凭证的仓库交给来历不明的第三方工具或者云端会话去分析。同时,SKILL.md里明确禁止AI执行任何“尝试利用漏洞”“绕过认证”“执行攻击脚本”的行为,我这里再强调一次,任何人都不应该把这类能力授予AI。安全审计的目标是发现问题、修复问题,不是攻破系统。把这条底线守住,这个技能包才真正有价值。
我把自己踩过的这些坑整理成了表格,方便你快速排查。
| 现象 | 常见原因 | 处理方式 |
|---|---|---|
| Skill未加载 | 目录路径错误或触发器不匹配 | 核对加载路径、重启会话、检查权限 |
| 报告内容空泛 | 没有引用规则文件 | 在SKILL.md步骤中明确要求读取规则文件 |
| 误报过高 | 未设白名单和分级 | 增加排除目录和严重级别区分 |
| 扫描覆盖不全 | 项目过大,AI只看了一部分 | 限定检查范围和必查模块 |
| AI输出不稳定 | 没有固定输出模板 | 在SKILL.md内置报告格式模板 |
说实话,最初把安全审计做成Skill,纯属是被反复“临时交代”磨得不耐烦了。真正做完之后我才意识到,最有价值的不是那几行脚本和规则文档,而是把大脑里零散的经验整理成了可以被复制、被迭代、被团队共享的资产。每次发现一个新的漏洞模式,我只需要往rules目录里加一条规则,这个技能包就比以前更聪明一点。如果你也准备给AI助手装一个类似的技能,我的建议是别想一步到位,先跑通最小闭环,再慢慢往里面喂规则。它不需要一开始就覆盖全世界,把一个框架搭起来,后续的沉淀会让你越用越顺手。