前言

Cursor 的 Agent Skill 机制允许你教会 AI 执行特定领域的专业任务。对于安全研究人员来说,一套精心设计的代码审计 Skill 体系可以将 Cursor 打造为高效的安全审计助手——自动化扫描危险模式、追踪数据流、生成标准化报告。

本文基于一套经过实战验证的 14 个安全审计 Skill 体系的设计与重构经验,系统讲解如何编写高质量的代码审计 Skill。


一、理解 Skill 机制

1.1 什么是 Skill

Skill 是 Markdown 文件,包含两部分:

  • 元数据(YAML frontmatter)namedescription,决定何时触发
  • 指令正文(Markdown body):教会 AI 如何执行审计任务

当用户请求匹配到 description 中的关键词时,Cursor 自动将 SKILL.md 加载到上下文。

1.2 存储位置

类型

路径

作用域

个人 Skill

~/.cursor/skills/skill-name/

所有项目可用

项目 Skill

.cursor/skills/skill-name/

仅当前项目

注意~/.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 元数据约束

字段

限制

说明

name

≤64字符,仅小写字母/数字/连字符

技能唯一标识符

description

≤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*\('

设计原则

  1. 按严重等级排序 — agent 优先扫描 P0,避免浪费时间在低危问题上
  2. 正则要精准 — 过宽的正则会产生大量误报,过窄的会漏报
  3. 覆盖完整攻击面 — 命令执行、代码执行、反序列化、SQL 注入、文件操作、SSRF 等
  4. 语言特定 — 每种语言的危险函数不同,不要跨语言复用
核心漏洞模式

用最简洁的方式展示危险代码安全替代的对比:

### 反序列化 (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 提供:

  1. 路由表 — 根据文件类型/框架快速选择正确的子 Skill
  2. 统一方法论 — 所有语言通用的审计流程
  3. 标准报告模板 — 所有子 Skill 共享的输出格式

6.3 合并与拆分决策

情况

决策

理由

Go + Kubernetes

合并为 code-audit-go-cloud

Go 与云原生强关联,用户往往同时需要

Python + SRC方法论

拆分:方法论入 master,Python模式入 python

方法论是通用的,不应绑定到单一语言

WAF绕过 + 密码学 + 移动安全

合并为 security-advanced

都是跨语言的进阶技术,单独成 Skill 太碎

Burp Suite

独立为 security-audit

有独立的工具集成(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 查询参数化
- [ ] 审计文件操作路径校验
- [ ] 检查框架配置
- [ ] 运行依赖审计工具
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐