【网络安全】编写代码审计
Cursor 的 Agent Skill 机制允许你教会 AI 执行特定领域的专业任务。对于安全研究人员来说,一套精心设计的代码审计 Skill 体系可以将 Cursor 打造为高效的安全审计助手——自动化扫描危险模式、追踪数据流、生成标准化报告。本文基于一套经过实战验证的 14 个安全审计 Skill 体系的设计与重构经验,系统讲解如何编写高质量的代码审计 Skill。元数据(YAML fron
前言
Cursor 的 Agent Skill 机制允许你教会 AI 执行特定领域的专业任务。对于安全研究人员来说,一套精心设计的代码审计 Skill 体系可以将 Cursor 打造为高效的安全审计助手——自动化扫描危险模式、追踪数据流、生成标准化报告。
本文基于一套经过实战验证的 14 个安全审计 Skill 体系的设计与重构经验,系统讲解如何编写高质量的代码审计 Skill。
一、理解 Skill 机制
1.1 什么是 Skill
Skill 是 Markdown 文件,包含两部分:
- 元数据(YAML frontmatter):
name和description,决定何时触发 - 指令正文(Markdown body):教会 AI 如何执行审计任务
当用户请求匹配到 description 中的关键词时,Cursor 自动将 SKILL.md 加载到上下文。
1.2 存储位置
|
类型 |
路径 |
作用域 |
|
个人 Skill |
|
所有项目可用 |
|
项目 Skill |
|
仅当前项目 |
注意:~/.cursor/skills-cursor/ 为 Cursor 内置保留,不要在此创建文件。
1.3 触发原理
Cursor 通过语义匹配 description 字段来决定激活哪个技能。这意味着:
- 描述中的关键词决定了匹配精度("PHP" "Laravel" "unserialize" 比 "代码审计" 更精准)
- 多个 Skill 可能同时被触发,因此描述要有区分度
- 描述质量直接决定 Skill 的可用性和误触率
二、文件结构
2.1 目录布局
skill-name/
├── SKILL.md # 必需 - 主指令文件(<500行)
├── reference.md # 可选 - 详细参考文档
├── payloads.md # 可选 - 漏洞载荷参考
└── examples.md # 可选 - 使用示例
2.2 SKILL.md 格式
---
name: skill-name
description: 第三人称描述。说明技能做什么以及何时使用。
---
# 技能标题
## 正文内容
2.3 元数据约束
|
字段 |
限制 |
说明 |
|
|
≤64字符,仅小写字母/数字/连字符 |
技能唯一标识符 |
|
|
≤1024字符,非空 |
触发匹配的核心 |
三、编写高质量描述
描述是 Skill 最重要的部分——写得好,精准触发;写得差,要么不触发,要么频繁误触。
3.1 核心原则
|
原则 |
说明 |
示例 |
|
第三人称 |
描述被注入系统提示中 |
"分析PHP源码漏洞" 而非 "我可以帮你分析" |
|
WHAT + WHEN |
同时说明能力和触发场景 |
"……当审计PHP代码或遇到unserialize时使用" |
|
包含触发词 |
列出语言/框架/漏洞类型关键词 |
"Laravel/ThinkPHP/WordPress" |
|
有区分度 |
避免与其他 Skill 描述高度重叠 |
每个语言 Skill 强调该语言特有的漏洞 |
3.2 好描述 vs 差描述
# 好 — 精准、有触发词、区分度高
description: >
PHP代码安全审计专家。分析PHP源码漏洞,支持Laravel/ThinkPHP/Symfony/
WordPress/Drupal等框架和CMS。当审计PHP代码或遇到unserialize/eval/
include/file_put_contents等危险函数时使用。
# 差 — 模糊、无区分度
description: 帮助审计代码安全
# 差 — 太长、堆砌关键词
description: >
这是一个非常全面的安全工具,可以帮助你分析PHP、Java、Python、Node.js、
Go、.NET的所有漏洞类型包括RCE、SQLi、XSS、CSRF、SSRF...
3.3 多 Skill 体系的描述策略
当你拥有一组相关 Skill 时,描述必须形成互斥的匹配域:
# 每个 Skill 强调自己的独特标识
code-audit-php: "...Laravel/ThinkPHP/WordPress...unserialize/eval/include..."
code-audit-java: "...Spring Boot/Struts2/MyBatis...反序列化/JNDI/SpEL/XXE..."
code-audit-python: "...Django/Flask/FastAPI...pickle/SSTI/eval/subprocess..."
code-audit-nodejs: "...Express/NestJS/Koa...原型链污染/NoSQLi/child_process..."
# 主索引的描述要覆盖"不确定用哪个"的场景
security-research-master: "...当需要代码审计、或不确定使用哪个安全技能时使用"
四、代码审计 Skill 的标准化结构
经过多轮迭代,我们总结出一套经过实战验证的标准化模板。所有语言审计 Skill 应遵循相同结构:
---
name: code-audit-{language}
description: {Language}代码安全审计专家。分析{Language}源码漏洞,支持{框架列表}。
当审计{Language}代码或遇到{特征漏洞列表}时使用。
---
# {Language} 代码审计
## 适用范围
[语言版本、框架、运行时]
## Grep 扫描规则 ← 核心创新:可执行的自动化规则
[按严重等级分类的正则表达式]
## 核心漏洞模式
[危险代码 vs 安全代码的对比示例]
## 框架审计要点
[各框架特有的漏洞检查点]
## 依赖审计
[包管理器的安全扫描命令]
## 审计检查清单
[结构化的 checklist]
4.1 各章节详解
适用范围
明确列出 Skill 覆盖的语言版本、框架、工具,帮助 agent 快速判断是否适用:
## 适用范围
- Python 2.x / 3.x 源代码
- Web框架:Django, Flask, FastAPI, Tornado, aiohttp
- 任务框架:Celery, Dramatiq
- ML/AI:Gradio, Streamlit, PyTorch serving
Grep 扫描规则(最关键的创新)
这是代码审计 Skill 最具价值的部分。它给 agent 提供了可直接用于 Grep 工具的正则表达式,实现自动化批量扫描。
按 SRC 严重等级组织:
P0_RCE: # 严重 - 远程代码执行
- 'eval\s*\('
- 'exec\s*\('
- 'pickle\.(loads?|load)\s*\('
- 'subprocess\.\w+\(.*shell\s*=\s*True'
- 'os\.(system|popen)\s*\('
P1_HIGH: # 高危 - SQLi/SSRF/路径穿越
- 'requests\.(get|post)\s*\('
- 'cursor\.execute\s*\(.*(%|\.format|f["\x27])'
- 'open\s*\(.*os\.path\.join'
- 'send_file\s*\('
P2_MEDIUM: # 中危 - 认证/信息泄露
- 'render_template_string\s*\('
- 'DEBUG\s*=\s*True'
- 'SECRET_KEY\s*=\s*["\x27]'
- '@csrf_exempt'
P3_LOW: # 低危 - XSS/弱配置
- 'redirect\s*\(.*request\.'
- 'random\.(randint|choice)\s*\('
设计原则:
- 按严重等级排序 — agent 优先扫描 P0,避免浪费时间在低危问题上
- 正则要精准 — 过宽的正则会产生大量误报,过窄的会漏报
- 覆盖完整攻击面 — 命令执行、代码执行、反序列化、SQL 注入、文件操作、SSRF 等
- 语言特定 — 每种语言的危险函数不同,不要跨语言复用
核心漏洞模式
用最简洁的方式展示危险代码和安全替代的对比:
### 反序列化 (P0)
\`\`\`python
# 危险 — pickle/yaml 均可 RCE
pickle.loads(untrusted_data)
yaml.load(data) # 默认 Loader 不安全
# 安全替代
json.loads(data)
yaml.safe_load(data)
\`\`\`
原则:
- 不要解释什么是反序列化(AI 知道)
- 不要写长段落描述危害(浪费 token)
- 只展示"什么样的代码有问题"和"应该怎么写"
- 注释简短——"危险"、"安全替代"足矣
框架审计要点
针对流行框架列出该框架特有的安全检查点:
### Django
\`\`\`python
# settings.py 检查项
DEBUG = True # 生产泄露
SECRET_KEY = 'hardcoded' # Session/Cookie 伪造
ALLOWED_HOSTS = ['*'] # Host 头注入
# 模板 XSS
{{ user_input|safe }}
{% autoescape off %}
# ORM 绕过: raw(), extra(), RawSQL
\`\`\`
审计检查清单
提供可勾选的 checklist,agent 可以按此流程逐项执行:
## 审计检查清单
- [ ] 使用 grep 规则批量扫描 P0-P3 模式
- [ ] 验证 eval/exec/compile 的输入来源
- [ ] 检查 pickle/yaml 反序列化入口
- [ ] 验证 SQL 查询参数化
- [ ] 审计文件操作路径校验
- [ ] 检查框架配置(DEBUG, SECRET_KEY, CORS)
- [ ] 运行依赖审计工具
五、设计原则
5.1 简洁为王
上下文窗口是有限资源。每一行内容都在与对话历史、其他 Skill 竞争空间。
核心判断标准:这条信息是 AI 本身不知道的吗?
|
应该写 |
不应该写 |
|
特定框架的漏洞模式 |
什么是 SQL 注入 |
|
Grep 扫描正则表达式 |
如何使用 grep 命令 |
|
框架版本对应的 CVE |
漏洞的完整利用过程 |
|
安全 vs 危险代码对比 |
基础安全概念解释 |
5.2 文件长度控制
SKILL.md 应控制在 200 行以内,最多不超过 500 行。
行数增加是可以接受的——前提是增加的是高价值的可执行内容(如 grep 规则),而不是冗余解释。
5.3 渐进式披露
将主文件保持精简,详细内容放到引用文件:
code-audit-php/
├── SKILL.md # 核心指令(~140行)
├── payloads.md # 漏洞载荷参考
└── frameworks.md # 框架审计详情
关键:引用链接保持一层深度。SKILL.md → reference.md 可以,但 SKILL.md → a.md → b.md 可能导致部分读取。
5.4 消除冗余
这是重构中最重要的教训。冗余有两种:
跨 Skill 冗余:相同内容出现在多个 Skill 中。
# 反面教材:master 中放了完整的危险函数速查表
# 每个语言 Skill 中也有相同的函数列表
# → 当两个 Skill 同时被加载时,上下文浪费翻倍
# 正确做法:
# master 只做路由和通用方法论
# 语言特定的函数列表只放在对应的语言 Skill 中
Skill 内冗余:代码注释中的废话。
# 差 — 注释是废话
system($cmd); // 这是一个危险的函数,它会执行系统命令!
# 好 — 注释言简意赅或不要注释
system($cmd);
六、模块化架构设计
6.1 分层架构
一套成熟的安全审计 Skill 体系应该是分层的:
Tier 1: 主索引
└── security-research-master ← 路由 + 统一方法论 + 报告模板
Tier 2: 代码审计(按语言)
├── code-audit-php ← 各语言独立 Skill
├── code-audit-java 每个都遵循标准化模板
├── code-audit-python 都包含 Grep 扫描规则
├── code-audit-nodejs
├── code-audit-dotnet
├── code-audit-go-cloud ← Go + 云原生 合并(强关联)
└── app-audit-electron ← 桌面应用审计
Tier 3: 专项审计
├── web-api-security ← JWT/OAuth/GraphQL/WebSocket
├── security-audit ← Burp Suite 动态测试
├── reverse-engineering ← IDA Pro / 二进制分析
└── firmware-security ← IoT / 固件 / 嵌入式
Tier 4: 跨语言进阶
└── security-advanced ← WAF绕过 / 竞态 / 密码学
6.2 主索引的设计
主索引(master)的职责是路由和方法论,不是内容百科全书。
错误做法:在 master 中放完整的危险函数速查表、反序列化速查表、框架漏洞表——这些与子 Skill 严重重复。
正确做法:
# 安全研究助手
## 技能路由(按语言选择)
| 识别特征 | 技能 |
|----------|------|
| .php / composer.json / Laravel | `code-audit-php` |
| .java / pom.xml / Spring | `code-audit-java` |
| .py / requirements.txt / Django | `code-audit-python` |
## 统一审计方法论
### Phase 1: 攻击面识别
### Phase 2: 漏洞扫描(按严重等级)
### Phase 3: 上下文验证
### Phase 4: 报告输出
[标准化报告模板]
Master 提供:
- 路由表 — 根据文件类型/框架快速选择正确的子 Skill
- 统一方法论 — 所有语言通用的审计流程
- 标准报告模板 — 所有子 Skill 共享的输出格式
6.3 合并与拆分决策
|
情况 |
决策 |
理由 |
|
Go + Kubernetes |
合并为 |
Go 与云原生强关联,用户往往同时需要 |
|
Python + SRC方法论 |
拆分:方法论入 master,Python模式入 python |
方法论是通用的,不应绑定到单一语言 |
|
WAF绕过 + 密码学 + 移动安全 |
合并为 |
都是跨语言的进阶技术,单独成 Skill 太碎 |
|
Burp Suite |
独立为 |
有独立的工具集成(MCP),与代码审计流程不同 |
七、与 MCP 工具集成
Cursor 支持 MCP(Model Context Protocol),可以在 Skill 中指导 agent 调用外部工具。
7.1 Burp Suite MCP
在 security-audit Skill 中集成 Burp Suite:
## 工具集成
| 工具 | 用途 |
|------|------|
| `get_scanner_issues` | 获取 Burp 扫描器发现的漏洞 |
| `get_proxy_http_history` | 查看代理捕获的请求历史 |
| `get_proxy_http_history_regex` | 按正则搜索流量 |
| `send_http1_request` | 手动发送 HTTP 请求测试 |
| `send_to_intruder` | 发送到 Intruder 模糊测试 |
## 审计工作流
### Phase 1: 侦察
1. `browser_navigate` → 目标 URL
2. `browser_snapshot` → 获取页面结构
3. `get_proxy_http_history` → 查看 Burp 捕获的请求
要点:列出工具名和用途的对照表,agent 才能知道该调用哪个工具。
7.2 IDA Pro MCP (ida-mcp-pro)
在 reverse-engineering Skill 中集成 IDA:
## ida-mcp-pro API
### 函数分析
ida_mcp_pro.get_function_list() -> List[dict]
ida_mcp_pro.decompile(address) -> str
ida_mcp_pro.get_xrefs_to(address) -> List[dict]
### 漏洞挖掘
ida_mcp_pro.find_dangerous_functions() -> List[dict]
ida_mcp_pro.trace_data_flow(source, sink, direction) -> dict
ida_mcp_pro.check_security_features() -> dict
要点:列出 API 签名和返回值类型,agent 才能正确使用。不需要解释函数做什么(名字已经说明了),只需要参数和返回值。
7.3 浏览器自动化
Cursor 内置的浏览器 MCP 可用于动态测试:
| 工具 | 用途 |
|------|------|
| `browser_navigate` | 访问目标 URL |
| `browser_snapshot` | 获取页面 DOM 结构 |
| `browser_take_screenshot` | 截图保存证据 |
| `browser_network_requests` | 监控网络请求 |
八、反模式与教训
这些是重构过程中发现的典型问题,编写新 Skill 时应避免。
8.1 "百科全书"型 Master
# 错误 — Master 变成了所有子 Skill 的摘要
## 危险函数速查表
| PHP | system, exec, eval... |
| Java | Runtime.exec, ObjectInputStream... |
| Python | eval, exec, pickle... |
## 反序列化速查
| PHP | unserialize, phar... |
| Java | ObjectInputStream, XStream... |
## 框架漏洞速查
| Laravel | RCE, Mass Assignment... |
| Spring | SpEL, Actuator... |
问题:这些内容与子 Skill 完全重复。当 master 和子 Skill 同时加载时,token 浪费翻倍。
解法:Master 只放路由表和方法论,具体模式放在各语言 Skill 中。
8.2 伪"通用" Skill
# 错误 — 名为"SRC高危漏洞审计",但 90% 内容是 Python
## P0 - 严重
eval(), exec(), pickle.loads(), yaml.load()
subprocess.Popen(shell=True), os.system()
## 语言特定规则
### Python
重点关注: eval/exec 链, pickle, subprocess, os.path.join...
问题:声称语言无关,实际内容 Python 偏重,与 code-audit-python 高度重叠。
解法:通用方法论归入 master,语言特定模式归入对应语言 Skill。
8.3 杂项堆积 Skill
# 错误 — 一个 Skill 塞了太多不相关主题
# 高级安全技术
## WAF绕过
## 竞态条件
## WASM安全
## 密码学审计
## Kubernetes安全 ← 已有 code-audit-go-cloud
## 容器逃逸 ← 已有 code-audit-go-cloud
## Serverless安全
## Android安全
## iOS安全
## Semgrep规则
## CI/CD集成
问题:主题过散,无法精准触发;与其他 Skill 存在重叠。
解法:去除与其他 Skill 重叠的内容,聚焦真正"跨语言"的高级技术。
8.4 冗余代码注释
// 差
const win = new BrowserWindow({
webPreferences: {
nodeIntegration: true, // 危险! 这个选项很危险!
contextIsolation: false, // 危险! 不要这样做!
enableRemoteModule: true, // 已弃用,这个也很危险
sandbox: false // 应为true
}
});
// 影响: 渲染进程XSS可直接执行Node.js代码
// 这意味着如果攻击者能注入XSS,就可以...(AI知道这些)
// 好
new BrowserWindow({
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
sandbox: false
}
});
// 影响: 渲染进程 XSS → require('child_process').exec('calc')
九、完整实战示例
以下是一个遵循标准化模板的完整 Skill 示例:
---
name: code-audit-python
description: Python代码安全审计专家。分析Python源码漏洞,支持Django/Flask/
FastAPI/Tornado等框架。当审计Python代码或遇到eval/exec/pickle/subprocess/
SSTI/yaml.load等问题时使用。
---
# Python 代码审计
## 适用范围
- Python 2.x / 3.x 源代码
- Web框架:Django, Flask, FastAPI, Tornado, aiohttp
- 任务框架:Celery, Dramatiq
- ML/AI:Gradio, Streamlit
## Grep 扫描规则
审计时先用以下正则批量搜索,再逐一验证上下文:
P0_RCE:
- 'eval\s*\('
- 'exec\s*\('
- 'pickle\.(loads?|load)\s*\('
- 'yaml\.load\s*\('
- 'subprocess\.\w+\(.*shell\s*=\s*True'
- 'os\.(system|popen)\s*\('
P1_HIGH:
- 'requests\.(get|post)\s*\('
- 'cursor\.execute\s*\(.*(%|\.format|f["\x27])'
- 'open\s*\(.*os\.path\.join'
- 'send_file\s*\('
P2_MEDIUM:
- 'render_template_string\s*\('
- 'DEBUG\s*=\s*True'
- 'SECRET_KEY\s*=\s*["\x27]'
## 核心漏洞模式
### 1. 反序列化 (P0)
# 危险 — pickle/yaml 均可 RCE
pickle.loads(untrusted_data)
yaml.load(data)
# 安全替代
json.loads(data)
yaml.safe_load(data)
### 2. SSTI 模板注入 (P0)
Template(user_input).render()
render_template_string(user_input)
# 安全: render_template("fixed.html", data=user_input)
### 3. SQL 注入 (P1)
cursor.execute(f"SELECT * FROM users WHERE id={uid}")
# 安全: cursor.execute("SELECT ... WHERE id=%s", (uid,))
## 框架审计要点
### Django
DEBUG = True / SECRET_KEY = 'hardcoded' / ALLOWED_HOSTS = ['*']
{{ user_input|safe }} / {% autoescape off %}
ORM 绕过: raw(), extra()
### Flask
FLASK_DEBUG=1 → 计算 PIN 可 RCE
app.secret_key 可预测 → Session 伪造
render_template_string(user_input) → SSTI
## 依赖审计
pip-audit -r requirements.txt
safety check -r requirements.txt
## 审计检查清单
- [ ] 使用 grep 规则批量扫描 P0-P3 模式
- [ ] 验证 eval/exec/compile 的输入来源
- [ ] 检查 pickle/yaml 反序列化入口
- [ ] 验证 SQL 查询参数化
- [ ] 审计文件操作路径校验
- [ ] 检查框架配置
- [ ] 运行依赖审计工具更多推荐
所有评论(0)