0. 写在前面:一个被忽视的边界
2026 年 7 月 16 日,The Hacker News 刊登了一篇标题为《AI Can Find Bugs, But Human Knowledge Still Proves Them》的文章。这篇文章并非讨论 AI 是否能找到漏洞——这一点在大量真实案例中已被证实——而是聚焦一个被行业刻意回避的问题:AI 报告的"漏洞"中,有多少能在真实部署环境中被证明存在?
答案并不乐观。在 THCon 2026 公开的一项对比研究中,445 个 AI 生成的漏洞候选最终只有 15% 通过人工验证;Claude-Sonnet-4 + Claude Code 工具链的误报率为 86%,GPT-04-mini + Codex 为 82%。与此同时,Bugcrowd 已公开承认正在处理 AI 生成的低质量报告激增问题,业内将其称为"AI slop" submissions。
本文不讨论"AI 是否会取代安全研究员"这种伪命题,而是给出可落地的工程答案:Lead 与 Finding 必须分离,AI 负责前者,人类负责后者,中间用一份可执行的验证清单连接。
1. AI 漏洞挖掘的现状:能力与局限
1.1 真实数据:AI 漏洞挖掘的误报率
THCon 2026 的研究使用了同一组真实目标代码,分别用两种主流 AI 工具链进行漏洞挖掘,并由人类研究员对所有候选进行验证。结果如下:
| 工具链 | 总发现数 | 误报数 | 误报率 | 有效发现数 |
|---|---|---|---|---|
| Claude-Sonnet-4 + Claude Code | 46 | ~40 | 86% | ~6 |
| GPT-04-mini + Codex | 21 | ~17 | 82% | ~4 |
| 研究整体(多模型汇总) | 445 | ~378 | 85% | ~67 |
数据来源:The Hacker News 2026-07-16 引用的 THCon 2026 研究报告。
需要注意几个工程含义:
- 更强的模型 ≠ 更低的误报率:Claude-Sonnet-4 的发现数量是 GPT-04-mini 的 2.2 倍,但误报率反而高出 4 个百分点。模型越能"流畅地编造证据",误报越难被初级研究员过滤。
- 绝对有效发现数仍在增长:即便误报率高达 86%,Claude 链仍然贡献了约 6 个被人类确认的真实漏洞。这意味着 AI 的价值不在于"判断准确性",而在于"扩大候选池"。
- 85% 这个数字是平均值:在不同漏洞类型上分布极不均匀。模式匹配类(如明显 SQL 拼接)误报率较低,可达性/业务逻辑类误报率可达 95% 以上。
1.2 AI 能做什么
将 AI 在漏洞挖掘中的能力边界明确化,是工程化的第一步。AI 真正擅长的是以下六类工作:
| 能力 | 工程价值 | 典型场景 |
|---|---|---|
| 快速阅读代码 | 在百万行代码库中定位关键路径 | 审计开源组件、合并代码 review |
| 生成 Payload | 基于已知模式快速产出测试输入 | Fuzzing 种子生成、PoC 初稿 |
| 总结攻击面 | 列出入口点、敏感函数、数据流方向 | 项目启动阶段的侦察 |
| 解释陌生 API | 即时给出 API 语义、危险参数、历史 CVE | 接触陌生框架时的加速器 |
| 执行重复性测试工作流 | 跑遍所有控制器、所有路由的相同检查 | OWASP Top 10 横扫 |
| 跨大代码库发现模式 | 找出散落在多处的相似危险写法 | 历史漏洞模式回溯 |
这六类工作有一个共同特征:它们的输出是 Lead(候选),不是 Finding(已验证漏洞)。
1.3 AI 不能做什么
同样需要明确的是 AI 在当前阶段无法替代人类完成的六类判断:
| 不能做的事 | 根本原因 | 后果 |
|---|---|---|
| 证明漏洞在部署环境中真实存在 | AI 看到的是源码切片,不是运行时 | 报告写得专业但无法复现 |
| 判断可达性 | 无法追踪 attacker-controlled input 是否真正到达 sink | 把不可达代码路径标为高危 |
| 理解身份边界和授权上下文 | 鉴权逻辑常散落在中间件、装饰器、网关 | 把已授权操作误判为越权 |
| 判断业务逻辑漏洞 | 业务规则不在代码字面中,在领域知识中 | 完全漏报最严重的漏洞类型 |
| 评估内存破坏的可利用性 | 需要堆布局、缓解措施、控制能力综合判断 | 把无害崩溃报为 RCE |
| 理解配置对漏洞暴露的影响 | 配置在代码之外,AI 默认看不到 | 把被网关/WAF 阻断的路径报为可达 |
这六类判断的共同特征是:它们都要求对系统的整体理解,而非对代码片段的局部推理。AI 的上下文窗口再大,也无法替代"这个功能在生产是否启用"这种事实判断。
2. "看起来有漏洞"≠"确实有漏洞"
这是当前 AI 漏洞挖掘最核心的问题。AI 擅长生成"看起来专业的报告"——格式规范、CVSS 评分、修复建议一应俱全——但它无法证明该漏洞在目标部署环境中真实存在。
2.1 三种最常见的 AI 误判
下表总结了 THCon 2026 研究中误报率最高的三类误判模式:
| AI 判断 | 实际情况 | 验证要点 |
|---|---|---|
| "SQL 注入" | 反射输入附近有数据库查询 | 可达性?预编译?编码?WAF? |
| "SSRF" | 代码中存在 URL fetch | 是否能访问受限资源?协议限制?响应过滤? |
| "RCE" | 代码路径中存在危险函数 | 可达性?参数控制?沙箱限制? |
这三类误判的共同根源是 AI 把"代码中存在某种模式"等同于"该模式可被攻击者利用"。
以 SQL 注入为例,AI 看到 $sql = "SELECT * FROM users WHERE id=" . $_GET['id'] 会立即标记为 SQL 注入。但它无法回答以下问题:
- 这个端点是否在公网暴露?
- 前面是否有鉴权中间件拦截未登录访问?
- 是否有 WAF 规则对
id参数做了模式过滤? - 是否有 ORM 层在执行前做了参数化?
- 数据库账号是否有
DROP权限? - 应用是否使用了只读副本?
任何一个问题答案为"否",都改变了漏洞的实际严重性。
2.2 可达性验证的六个关键问题
可达性(reachability)是 Lead 与 Finding 之间的核心分界线。在确认任何 AI 候选之前,必须回答以下六个问题:
-
攻击者控制的输入是否真正到达危险操作?
- 数据流从 HTTP 入口到 sink 之间是否经过过滤、转义、类型强转?
- 中间是否有不可绕过的 sanitizer?
-
是否需要认证?
- 攻击者是否能以匿名身份到达该代码路径?
- 如果需要认证,是否任何已注册用户都能触发?
-
授权是否在其他地方执行?
- 是否有装饰器、中间件、网关层做了 RBAC/ABAC?
- 跨租户访问是否在数据层而非应用层隔离?
-
漏洞功能是否启用?
- 该路由是否在
routes.py中注册? - 是否被 feature flag 关闭?
- 是否在当前部署版本中存在?
- 该路由是否在
-
生产配置是否暴露该代码路径?
- 测试环境的端点是否在生产环境中可达?
- 是否被 ingress controller / API gateway 拦截?
- 是否仅在内部服务网格中暴露?
-
应用是否在关键点进行规范化/编码/过滤/拒绝?
- 输出端是否有 CSP、HTML encode?
- 输入端是否有 length limit、charset check、regex pattern?
- 数据库层是否有 stored procedure 强制类型?
这六个问题任一回答不上来,候选就不能升级为 Finding。
2.3 影响评估的陷阱
即使漏洞真实存在,AI 对其影响的评估也常常严重失真。三种典型陷阱:
陷阱一:反射输入 ≠ XSS
// AI 标记为 XSS 漏洞
res.send(`<div>User: ${req.query.name}</div>`);
AI 报告会写"反射型 XSS,CVSS 6.1"。但实际验证需要回答:
- 响应头
Content-Type是否为text/html?若是text/plain则浏览器不解析。 - 是否有 CSP 头
script-src 'self'阻止内联脚本? - 是否有
X-Content-Type-Options: nosniff? - 输出前是否有
escapeHtml()调用?模板引擎是否默认转义? - 浏览器是否在当前 SOP 下解析该响应?
只有当上述全部满足且能实际弹出 alert(1),才是 XSS。
陷阱二:URL fetch ≠ SSRF
# AI 标记为 SSRF
import requests
resp = requests.get(user_provided_url)
AI 报告会写"SSRF,可访问内网"。但实际验证需要回答:
- 是否有出网防火墙限制目标 IP 段?
- 是否有协议白名单(只允许 http/https)?
- 是否在 fetch 前对 IP 做了 DNS 解析并拒绝内网段?
- 响应是否返回给攻击者?若不返回,仅是无回显 SSRF,影响有限。
- 是否使用了 cloud metadata 防护(如 IMDSv2)?
只有当能实际访问 http://169.254.169.254/latest/meta-data/ 并拿到 IAM 凭证,才是有意义的 SSRF。
陷阱三:危险函数 ≠ RCE
# AI 标记为 RCE
import os
os.system(user_input)
AI 报告会写"命令注入,CVSS 9.8"。但实际验证需要回答:
user_input是否真的攻击者可控?还是来自配置文件、环境变量、内部 RPC?- 是否在到达此行前被
shlex.quote()处理? - 进程是否在 seccomp/AppArmor/容器沙箱中?沙箱是否禁用了 execve?
- 该函数是否在死代码区,从未被实际调用?
- 该端点是否在生产部署中暴露?
CVSS 9.8 的评分可能是完全错误的——它基于"漏洞存在且完全可利用"的假设,而这个假设正是 AI 无法验证的部分。
3. AI 漏洞挖掘的工程化框架
将上述原则工程化的关键是建立 Lead → Finding 的两阶段工作流,并辅以三阶段流水线和二次校验机制。
3.1 Lead → Finding 的两阶段工作流
┌──────────────────────────────────────────────────────────────────┐
│ 阶段 A:AI 生成候选(Lead) │
│ ├─ 输入:代码库、配置、攻击面描述 │
│ ├─ 操作:模式匹配 + 语义分析 + 历史漏洞类比 │
│ └─ 输出:候选列表(含位置、假设、初步信心) │
└──────────────────────────────────────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────────────────┐
│ 阶段 B:人工验证(Finding 升级) │
│ ├─ 验证清单逐项检查 │
│ │ ├─ 具体行为? │
│ │ ├─ 攻击者控制? │
│ │ ├─ 安全边界? │
│ │ ├─ 复现步骤? │
│ │ ├─ 实际影响? │
│ │ └─ 修复方案? │
│ └─ 输出:确认漏洞 / 误报 / 待定 │
└──────────────────────────────────────────────────────────────────┘
这个工作流的核心是 候选与漏洞是两个不同的工件,必须用不同的工件管理系统跟踪。Bugcrowd 等众测平台已在 2026 年初调整其提交界面,要求研究员明确标注"AI 生成候选"或"已验证漏洞",并对外公开处理 AI slop 的政策。
3.2 三阶段 AI 漏洞挖掘流水线
将两阶段工作流进一步细化为可执行的流水线:
┌─────────────────────────────────────────────────────────────────┐
│ 阶段 1:全局侦察收集 │
│ ├─ 攻击面识别(入口点、API、文件上传、Webhook) │
│ ├─ 代码结构分析(依赖图、调用图、模块边界) │
│ ├─ 技术栈指纹(框架版本、库版本、已知 CVE 关联) │
│ └─ 配置收集(环境变量、feature flags、部署拓扑) │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 阶段 2:双线审计分析 │
│ ├─ 线 A:静态分析(CodeQL、Semgrep、Joern) │
│ │ └─ 输出:基于规则的高置信度 Lead │
│ └─ 线 B:AI 语义分析(LLM + 代码上下文) │
│ └─ 输出:基于语义推理的候选 Lead │
│ │
│ 两线结果合并去重 → 统一进入阶段 3 │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────────┐
│ 阶段 3:攻击路径验证 │
│ ├─ 动态验证(沙箱中执行 PoC) │
│ ├─ PoC 构建(基于 Lead 自动生成 + 人工调整) │
│ └─ 影响确认(实际数据泄露 / 命令执行 / 越权访问证据) │
│ │
│ 输出:Finding(含复现步骤、影响证据、修复建议) │
└─────────────────────────────────────────────────────────────────┘
阶段 2 的"双线审计"是关键设计:静态分析工具(CodeQL、Semgrep)的输出虽然保守,但误报率可控;AI 的输出虽然覆盖面广,但误报率高。两者交叉验证可显著降低进入阶段 3 的候选数量。
3.3 CodeBuddy Security 的二次校验机制
CodeBuddy Security 提出了一种值得借鉴的二次校验(second-pass verification)机制。其核心思想是:用独立的 AI 上下文从零开始重新校验前序 AI 的发现,而非在前序上下文基础上继续推理。
这与人类研究员的"自我证伪"过程一致:当研究员 A 报告一个漏洞,研究员 B 不应只看 A 的报告然后点头,而应独立地从代码出发重新构造攻击路径。
二次校验的 Prompt 设计示例:
你是一个独立的漏洞验证员。你将收到一段代码和一个声称的漏洞。
你的任务是【证伪】该漏洞,而非证实它。
对于声称的漏洞,你必须回答:
1. 在代码中找出所有阻止该漏洞被利用的防御措施(编码、过滤、鉴权、配置)。
2. 列出攻击者要触发该漏洞必须满足的所有前置条件。
3. 对每个前置条件,判断其在标准生产部署中是否成立。
4. 若有任何前置条件不成立,输出"已证伪"并说明原因。
5. 若所有前置条件均成立,输出"未证伪",但仍需人类进一步验证。
声称的漏洞:
{vulnerability_claim}
代码:
{code_snippet}
部署配置(如可用):
{deployment_config}
输出 JSON:
{
"falsified": true/false,
"defenses_found": [...],
"preconditions": [...],
"preconditions_met_in_production": [...],
"reasoning": "..."
}
这个 Prompt 的关键设计点:
- 角色为"验证员"而非"分析员":避免与前序分析员产生立场一致性偏差。
- 任务为"证伪"而非"证实":利用 AI 在反驳任务上的表现优于证实任务的特性(confirmation bias 反向利用)。
- 必须列出防御措施:强制 AI 主动寻找反例,而非被动接受声称。
- 输出结构化 JSON:便于下游程序化判断与统计。
CodeBuddy Security 的实践数据显示,二次校验机制能将进入人工验证阶段的候选数量再降低 40-60%,但代价是额外的 LLM 调用开销。在工程上这是一个值得的权衡,因为人工验证的成本远高于 LLM 调用。
重要约束:根据行业实践,以下三类漏洞禁止 AI 全自动修复,必须人类全程介入:
- 核心业务逻辑漏洞:涉及资金、权限、计费的逻辑缺陷,AI 修复可能引入新的业务不一致。
- 高危可利用漏洞:RCE、SQL 注入(root 权限)、认证绕过等,修复方案必须在测试环境完整复测。
- 架构级缺陷:跨服务的信任边界问题、租户隔离缺陷,AI 单点修复无法解决系统性问题。
4. 验证清单:从 Lead 到 Finding 的七步法
4.1 完整验证清单
以下清单改编自 The Hacker News 2026-07-16 文章提出的核心要素,已扩展为可直接在工单系统中使用的检查表:
□ 1. 观察到的具体行为是什么?在哪里发生?
- 必须能指出代码行、函数、模块、HTTP 路由
- 不能用"可能存在"模糊表述
□ 2. 需要什么攻击者控制的输入、身份或状态?
- 攻击者控制的具体参数名
- 所需身份(匿名 / 已注册 / 管理员 / 内部服务)
- 所需前置状态(已创建资源、特定时间窗口、特定配置)
□ 3. 跨越了什么安全边界?
- 认证边界(未登录 → 已登录)
- 授权边界(普通用户 → 管理员)
- 租户边界(租户 A → 租户 B)
- 信任边界(外部 → 内部)
- 特权边界(用户态 → 内核态)
- 内存安全边界(只读 → 可写)
□ 4. 在目标环境中复现的确切步骤是什么?
- 必须能在 staging 环境完整复现
- 包含 curl 命令或 HTTP 请求原始报文
- 包含预期响应与实际响应的对比
□ 5. 实际影响是什么?
- 不是 CVSS 理论最坏情况
- 是"攻击者实际能做什么"的具体描述
- 包含数据敏感度、影响用户范围、横向移动可能性
□ 6. 什么证据表明该问题在部署配置中可达且相关?
- 生产配置截图、路由表、防火墙规则
- 沙箱中实际触发的日志
- 监控系统中可观察的异常
□ 7. 修复需要改变什么?如何确认修复有效?
- 具体代码改动(diff)
- 修复后的复现尝试必须失败
- 回归测试用例
七项全部勾选,方可标记为 Confirmed Finding;缺任一项,标记为 Lead - Pending Validation。
4.2 各漏洞类型的验证重点
不同漏洞类型,AI 擅长发现的部分和人类必须验证的部分差异巨大:
| 漏洞类型 | AI 擅长发现 | 人类必须验证 |
|---|---|---|
| SQL 注入 | 拼接模式识别 | 预编译使用、WAF 过滤、可达性、DB 权限 |
| XSS | 反射点识别 | CSP 策略、编码有效性、执行证明、Content-Type |
| SSRF | URL fetch 定位 | 内网可达性、协议限制、响应过滤、IMDS 防护 |
| RCE | 危险函数识别 | 可达性、参数控制、沙箱限制、调用频率 |
| 认证绕过 | 逻辑异常识别 | 完整认证链、会话管理、令牌验证、刷新机制 |
| 内存破坏 | 危险模式识别 | 崩溃可利用性、缓解措施(ASLR/CFI/DEP)、控制能力 |
| 业务逻辑 | 流程异常提示 | 业务规则、资金影响、对账机制、审计日志 |
| 反序列化 | 反序列化点定位 | 类白名单、类型限制、触发条件、链可达性 |
注意最后一行"业务逻辑"——AI 在这一类型上几乎无能为力。业务逻辑漏洞是当前 AI 漏洞挖掘最大的盲区,也是人类研究员不可替代的核心价值所在。
5. AI 辅助漏洞挖掘的实战代码
以下三个代码示例构成一个最小可运行的 Lead → Finding 流水线。所有代码使用 Python 3.10+,依赖 openai SDK(兼容 OpenAI 协议的任意端点,包括 Claude、DeepSeek、本地 vLLM)。
5.1 AI 漏洞候选生成器
"""
AI 漏洞候选生成器
输入:代码片段 + 上下文
输出:结构化 Lead 列表
"""
import json
import os
from openai import OpenAI
client = OpenAI(
api_key=os.environ["LLM_API_KEY"],
base_url=os.environ.get("LLM_BASE_URL", "https://api.openai.com/v1"),
)
LEAD_GEN_PROMPT = """你是安全研究员。分析以下代码,识别潜在漏洞。
对每个发现,输出 JSON 对象,包含字段:
- vulnerability_type: 漏洞类型(如 SQLi/XSS/SSRF/RCE/PathTraverse/AuthBypass)
- location: 代码位置(文件:行号 或函数名)
- description: 漏洞描述(一段话)
- hypothesis: 为什么认为有漏洞(基于代码模式的具体推理)
- validation_steps: 需要人工验证的步骤列表
- attacker_control: 攻击者需要控制的输入/身份/状态
- confidence: 初步信心(low/medium/high)
要求:
1. 不要输出"看起来像漏洞"的猜测,必须有具体代码依据。
2. 必须列出验证步骤,否则该候选将被自动丢弃。
3. confidence 为 high 的发现,必须能在静态分析层面找到完整数据流。
代码:
{code_snippet}
上下文:
{context}
只输出 JSON 数组,不要任何额外文字。
"""
def generate_vuln_candidates(code_snippet: str, context: str) -> list[dict]:
"""生成漏洞候选列表"""
prompt = LEAD_GEN_PROMPT.format(
code_snippet=code_snippet,
context=context,
)
response = client.chat.completions.create(
model=os.environ.get("LLM_MODEL", "claude-sonnet-4-20250514"),
messages=[{"role": "user", "content": prompt}],
response_format={"type": "json_object"},
temperature=0.2,
)
raw = response.choices[0].message.content
try:
data = json.loads(raw)
# 兼容两种返回格式:直接数组 或 {"findings": [...]}
if isinstance(data, list):
return data
return data.get("findings", data.get("candidates", []))
except json.JSONDecodeError:
return []
if __name__ == "__main__":
code = '''
@app.route("/profile")
def profile():
user_id = request.args.get("id")
query = f"SELECT * FROM users WHERE id = {user_id}"
user = db.execute(query).fetchone()
return render_template("profile.html", user=user)
'''
ctx = "Flask 应用,db 是 SQLAlchemy session,无 WAF,部署在 AWS ALB 后"
leads = generate_vuln_candidates(code, ctx)
print(json.dumps(leads, indent=2, ensure_ascii=False))
预期输出(节选):
[
{
"vulnerability_type": "SQLi",
"location": "profile():query",
"description": "user_id 直接拼接进 SQL 字符串,未参数化",
"hypothesis": "request.args.get('id') 未经类型转换直接 f-string 拼接",
"validation_steps": [
"确认 /profile 路由在公网暴露",
"确认无中间件对 id 做整数校验",
"确认 db.execute 不在 ORM 层做参数化",
"构造 ?id=1 OR 1=1 复现"
],
"attacker_control": "匿名 HTTP 请求的 id 参数",
"confidence": "high"
}
]
注意:confidence=high 不代表它是 Finding,只代表它值得进入验证阶段。
5.2 人工验证辅助工具
"""
验证清单自动检查器
对每个 Lead 执行七步检查,输出可升级为 Finding 的候选
"""
from dataclasses import dataclass, field
@dataclass
class ValidationChecklist:
specific_behavior: bool = False
attacker_control: bool = False
security_boundary: bool = False
repro_steps: bool = False
actual_impact: bool = False
reachability: bool = False
fix_plan: bool = False
def completeness(self) -> float:
return sum(
getattr(self, f) for f in [
"specific_behavior", "attacker_control", "security_boundary",
"repro_steps", "actual_impact", "reachability", "fix_plan",
]
) / 7
class VulnValidator:
"""对单个 Lead 执行验证清单检查"""
REQUIRED_FIELDS = {
"specific_behavior": ["location", "behavior"],
"attacker_control": ["attacker_control"],
"security_boundary": ["boundary_crossed"],
"repro_steps": ["repro_steps"],
"actual_impact": ["actual_impact"],
"reachability": ["reachability_evidence"],
"fix_plan": ["fix_diff"],
}
def __init__(self, lead: dict, validation_report: dict):
self.lead = lead
self.report = validation_report
self.checklist = ValidationChecklist()
def validate(self) -> dict:
for item, required_keys in self.REQUIRED_FIELDS.items():
all_present = all(k in self.report and self.report[k] for k in required_keys)
setattr(self.checklist, item, all_present)
confidence = self.checklist.completeness()
return {
"lead_id": self.lead.get("location"),
"validated": confidence >= 0.85, # 6/7 以上才算通过
"confidence": round(confidence, 2),
"missing_items": [
item for item in self.REQUIRED_FIELDS
if not getattr(self.checklist, item)
],
"details": self.checklist.__dict__,
}
if __name__ == "__main__":
lead = {
"vulnerability_type": "SQLi",
"location": "profile():query",
"attacker_control": "匿名 HTTP 请求的 id 参数",
}
report = {
"location": "profile():query",
"behavior": "未参数化 SQL 拼接",
"attacker_control": "匿名 HTTP 请求的 id 参数",
"boundary_crossed": "未认证 → 数据库读",
"repro_steps": "curl 'https://target/profile?id=1 OR 1=1'",
"actual_impact": "全表 users 数据泄露(含 password_hash)",
"reachability_evidence": "ALB 日志显示该路由在公网开放",
"fix_diff": "改用 db.session.execute(text('SELECT ... WHERE id=:id'), {'id': int(user_id)})",
}
result = VulnValidator(lead, report).validate()
print(result)
# {'validated': True, 'confidence': 1.0, 'missing_items': [], ...}
该工具不替代人工判断,它只确保研究员在提交 Finding 前已填齐所有必要字段。任何 missing_items 非空的 Lead 都会被工单系统自动退回。
5.3 自动化 PoC 生成与验证
"""
自动生成 PoC 并在隔离沙箱中验证
仅用于 staging 环境,禁止用于生产
"""
import subprocess
import json
from dataclasses import dataclass
@dataclass
class SandboxResult:
status: str # crash / data_leak / code_exec / no_effect / error
stdout: str = ""
stderr: str = ""
data: dict = None
exit_code: int = 0
def llm_generate_poc(vulnerability: dict, target_base_url: str) -> str:
"""调用 LLM 生成 PoC 脚本"""
prompt = f"""生成一个 Python PoC 脚本,验证以下漏洞。
只输出可执行 Python 代码,不要任何说明文字。
目标地址:{target_base_url}
漏洞信息:
{json.dumps(vulnerability, ensure_ascii=False, indent=2)}
要求:
1. 使用 requests 库
2. 输出 JSON 格式结果:{{"status": "...", "evidence": "..."}}
3. status 取值:data_leak / code_exec / no_effect / error
4. 不要使用 print,将结果写入 stdout
"""
from openai import OpenAI
import os
client = OpenAI(api_key=os.environ["LLM_API_KEY"])
resp = client.chat.completions.create(
model=os.environ.get("LLM_MODEL", "claude-sonnet-4-20250514"),
messages=[{"role": "user", "content": prompt}],
)
return resp.choices[0].message.content
def execute_in_sandbox(poc_code: str, target_env: dict) -> SandboxResult:
"""在 Docker 沙箱中执行 PoC,限制网络与资源"""
sandbox_image = "poc-sandbox:latest" # 预构建:仅含 python+requests,无外网
container_name = f"poc-{hash(poc_code) & 0xFFFFFFFF:x}"
# 将 PoC 写入容器,限制 CPU/内存/网络
cmd = [
"docker", "run", "--rm",
"--name", container_name,
"--memory=256m", "--cpus=0.5",
"--network=poc_net", # 仅能访问 staging 目标
"--read-only",
"--cap-drop=ALL",
"-e", f"TARGET_URL={target_env['url']}",
sandbox_image,
"python", "-c", poc_code,
]
proc = subprocess.run(cmd, capture_output=True, text=True, timeout=30)
if proc.returncode != 0:
return SandboxResult(status="error", stderr=proc.stderr, exit_code=proc.returncode)
try:
payload = json.loads(proc.stdout)
return SandboxResult(
status=payload.get("status", "no_effect"),
stdout=proc.stdout,
data=payload,
)
except json.JSONDecodeError:
return SandboxResult(status="error", stderr=proc.stdout)
def verify_finding(vulnerability: dict, target_env: dict) -> dict:
"""完整 Lead → Finding 验证流程"""
# 1. AI 生成 PoC
poc = llm_generate_poc(vulnerability, target_env["url"])
# 2. 沙箱执行
result = execute_in_sandbox(poc, target_env)
# 3. 根据结果分类
if result.status == "data_leak":
verified = verify_data_sensitivity(result.data)
elif result.status == "code_exec":
verified = True # 沙箱中执行任意代码即确认 RCE
elif result.status == "crash":
verified = verify_exploitability(result)
else:
verified = False
return {
"vulnerability": vulnerability,
"poc": poc,
"sandbox_result": result.status,
"verified": verified,
"evidence": result.data,
}
def verify_data_sensitivity(data: dict) -> bool:
"""检查泄露数据是否包含敏感字段"""
sensitive_keys = {"password", "password_hash", "token", "secret", "ssn", "credit_card"}
if not data:
return False
leaked = str(data).lower()
return any(k in leaked for k in sensitive_keys)
def verify_exploitability(result: SandboxResult) -> bool:
"""对崩溃结果做可利用性初判(人类必须复核)"""
# 仅做粗筛:崩溃信号、寄存器控制等
if "SIGSEGV" in result.stderr or "EIP" in result.stderr:
return True # 候选,需人类进一步分析
return False
if __name__ == "__main__":
vuln = {
"vulnerability_type": "SQLi",
"location": "profile():query",
"attacker_control": "匿名 HTTP 请求的 id 参数",
}
env = {"url": "http://staging-target:8080"}
report = verify_finding(vuln, env)
print(json.dumps(report, indent=2, ensure_ascii=False, default=str))
三个脚本串联起来即可构成最小可运行流水线:generate_vuln_candidates → 人工填验证报告 → VulnValidator.validate → verify_finding 沙箱复现。
工程注意事项:
- 沙箱必须只与 staging 通信,禁止访问生产、禁止访问公网。
- PoC 代码以字符串形式注入容器,避免宿主机文件系统污染。
verify_exploitability只做粗筛,任何返回 True 的崩溃都需要人类用 GDB/WinDbg 复核。- 生成 PoC 的 LLM 调用必须走独立账户,避免与生成 Lead 的调用共享上下文。
6. AI 让安全研究员"生疏"的风险
这是 The Hacker News 文章中被低估的一个议题。AI 不仅改变工作流,还在持续改变研究员的能力结构。
6.1 过度依赖的三个表现
| 表现 | 短期效应 | 长期风险 |
|---|---|---|
| 不再记忆细节 | AI 即时回答所有问题 | 失去"看到代码即联想漏洞"的肌肉记忆 |
| 不再练习脚本编写 | AI 生成第一版 | 失去调试、定制、扩展能力 |
| 不再构建心智模型 | AI 解释所有代码路径 | 失去跨系统、跨层的整体判断能力 |
这三项能力的衰退是渐进且不可见的——研究员不会感到"我不会了",只会感到"我需要 AI 才能做"。当遇到 AI 无法处理的场景时,差距才会暴露。
6.2 为什么这很危险
四个具体原因:
-
深度漏洞发现依赖模式识别和技术回忆。AI 擅长的模式是"已知的已知",而真正的深度漏洞(如 Spectre、Log4Shell)来自"已知的未知"——研究员需要在没有先例的情况下识别异常。
-
最难的发现来自"一个领域的行为违反了另一个领域的假设"。例如,HTTP/2 的流复用在网络层是正常的,但在应用层可能导致请求走私;TLS 的会话复用在加密层是优化的,但在身份层可能导致认证绕过。这种跨领域的异常识别,AI 当前无法做到。
-
工具输出从来不够,需要理解信号的含义。Fuzzer 给出的崩溃只是信号,是否可利用需要研究员理解堆布局、CPU 流水线、内核缓解措施。AI 可以读 crash log,但无法判断"这个 crash 是否值得追下去"。
-
第一次尝试失败时,理解系统的人能适应,依赖工具的人会卡住。当 PoC 在 staging 不生效时,理解系统的人会调整输入、绕过 WAF、利用时序差;依赖工具的人只会重新跑一次 AI,得到几乎相同的结果。
6.3 保持技能的策略
| 角色 | 策略 |
|---|---|
| 初级研究员 | 先学基础再外包。在能用 AI 之前,必须能徒手完成 OWASP Top 10 复现、CodeQL 基础查询、Burp 全流程操作。 |
| 高级研究员 | 用 AI 作为力量倍增器而非权威。AI 输出永远是候选,最终判断权在自己。 |
| 团队 | 不仅审查发现是否生成,还要审查研究员能否解释和复现。无法解释的 Finding 不计入绩效。 |
| 项目级 | 健康的 AI 辅助测试项目应奖励"验证的影响"而非"发现的数量"。Bugcrowd 已开始调整其 bounty 模型,对 AI slop 提交做降权处理。 |
7. 团队级 AI 漏洞挖掘最佳实践
7.1 角色分工
| 角色 | 职责 | AI 使用方式 |
|---|---|---|
| 初级研究员 | 执行验证清单、复现 PoC | AI 辅助理解代码、解释陌生 API |
| 高级研究员 | 判断可利用性、构造复杂 PoC | AI 加速假设生成、跨代码库模式搜索 |
| 安全架构师 | 评估业务影响、设计修复方案 | AI 辅助攻击面分析、依赖图梳理 |
| AI 系统 | 生成 Lead、二次校验 | 不做最终判断,输出必须经人类签字 |
关键原则:AI 系统永远不是责任主体。任何 Finding 的责任必须落在具名人类研究员身上,这与代码 review 中"AI 生成的代码必须由人类署名"的原则一致。
7.2 工作流设计
阶段 1: AI 扫描 → 生成候选(Lead)
└─ 输入:代码库 + 配置 + 攻击面描述
└─ 输出:Lead 列表(含位置、假设、信心分)
└─ 退出条件:候选数 ≥ 1 或扫描完成
阶段 2: 初级研究员 → 执行验证清单
└─ 操作:填齐七步检查表
└─ 工具:VulnValidator 自动校验完整性
└─ 退出条件:confidence ≥ 0.85 或标记为误报
阶段 3: 高级研究员 → 判断可利用性
└─ 操作:构造 PoC、在 staging 复现
└─ 工具:5.3 节沙箱
└─ 退出条件:成功复现或证伪
阶段 4: 架构师 → 评估业务影响
└─ 操作:判断影响用户数、资金风险、合规风险
└─ 退出条件:输出影响等级(P0/P1/P2)
阶段 5: 修复团队 → 确认修复有效
└─ 操作:应用补丁、重新执行 PoC
└─ 退出条件:PoC 失败 + 回归测试通过
每个阶段必须留下可审计的工件(Lead 列表、验证报告、PoC 脚本、影响评估、修复 diff)。这些工件是后续误报分析与流程改进的基础。
7.3 质量度量指标
只数发现数量是危险的——它会激励研究员和 AI 系统都倾向于多报、宽报。正确的度量指标体系:
| 指标 | 定义 | 目标 |
|---|---|---|
| Lead → Finding 转化率 | Finding 数 / Lead 数 | 15-30% 为健康区间 |
| 平均验证耗时 | 从 Lead 生成到 Finding 确认的小时数 | 越低越好,但不应低于 2 小时 |
| 误报对工程信任的侵蚀率 | 工程团队对安全团队提出的修复请求数 / 总 Finding 数 | 低于 10% 为健康 |
| AI 候选召回率 | AI 发现的 Lead 中包含真实漏洞的比例 | 与人工审计对比,目标 ≥ 80% |
| 独立发现率 | 人类研究员在未看 AI 输出情况下独立发现的漏洞数 | 不应降为 0,否则团队已过度依赖 |
最后一项"独立发现率"尤其重要——它衡量的是团队能力是否在退化。一个健康的团队,AI 辅助后的独立发现率不应低于 AI 辅助前的 60%。
8. 未来展望:AI 与人类的协作演进
AI Agent 的能力正在快速提升:导航应用界面、读取代码、生成 Payload、文档化结果——这些任务在 2024 年还需要人类辅助,2026 年已可半自动完成。但 核心标准不变:Prove it(证明它)。
证明什么?五件事:
- 证明漏洞存在——不是"代码看起来有",而是"在运行环境中确实有"。
- 证明攻击者可达——不是"理论上可达",而是"在当前部署配置下实际可达"。
- 证明影响——不是"CVSS 9.8",而是"攻击者实际能造成的具体损害"。
- 证明业务风险——不是"漏洞严重",而是"对资金、用户、合规的具体后果"。
- 证明修复有效——不是"代码改了",而是"PoC 在修复后失败,且无回归"。
这五件事,每一件都需要人类用系统知识、领域知识、运行时观察来证明。AI 可以加速其中某些环节(如自动生成 PoC、自动跑回归),但最终的"证明"动作必须由人类完成。
最好的研究者和团队,永远是 自动化 + 技术判断 的结合。知道何时停止、何时检查、何时测试、何时思考——这种判断力将保持长期竞争优势。
THCon 2026 的 445 个发现中,最终被证明存在的 67 个漏洞,每一个都经过了人类的七步验证。AI 提供了 445 个起点,人类把它们变成了 67 个事实。这个比例在可预见的未来不会发生根本改变——因为漏洞验证的本质是"对真实系统的理解",而理解这件事,AI 当前做不到,中短期内也不会做到。
参考资料
- The Hacker News. AI Can Find Bugs, But Human Knowledge Still Proves Them. 2026-07-16.
- THCon 2026. Comparative Study of LLM-Assisted Vulnerability Discovery Pipelines.
- Bugcrowd. Handling AI-Generated Submission Surge: Platform Policy Update. 2026.
- CodeBuddy Security. Second-Pass Verification for LLM Security Findings. Technical Report.
- OWASP. Automated Threat Handbook — LLM-Assisted Testing Chapter. 2026 ed.
本文核心立场:AI 把漏洞挖掘从"找候选"变成了"流水线生产候选",但"证明候选是漏洞"这一步,仍然、且在可预见未来仍将,是人类研究员的核心价值。把 Lead 当 Finding 提交,是当前 AI 漏洞挖掘最大的工程错误。
浙公网安备 33010602011771号