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 研究报告。

需要注意几个工程含义:

  1. 更强的模型 ≠ 更低的误报率:Claude-Sonnet-4 的发现数量是 GPT-04-mini 的 2.2 倍,但误报率反而高出 4 个百分点。模型越能"流畅地编造证据",误报越难被初级研究员过滤。
  2. 绝对有效发现数仍在增长:即便误报率高达 86%,Claude 链仍然贡献了约 6 个被人类确认的真实漏洞。这意味着 AI 的价值不在于"判断准确性",而在于"扩大候选池"。
  3. 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 候选之前,必须回答以下六个问题:

  1. 攻击者控制的输入是否真正到达危险操作?

    • 数据流从 HTTP 入口到 sink 之间是否经过过滤、转义、类型强转?
    • 中间是否有不可绕过的 sanitizer?
  2. 是否需要认证?

    • 攻击者是否能以匿名身份到达该代码路径?
    • 如果需要认证,是否任何已注册用户都能触发?
  3. 授权是否在其他地方执行?

    • 是否有装饰器、中间件、网关层做了 RBAC/ABAC?
    • 跨租户访问是否在数据层而非应用层隔离?
  4. 漏洞功能是否启用?

    • 该路由是否在 routes.py 中注册?
    • 是否被 feature flag 关闭?
    • 是否在当前部署版本中存在?
  5. 生产配置是否暴露该代码路径?

    • 测试环境的端点是否在生产环境中可达?
    • 是否被 ingress controller / API gateway 拦截?
    • 是否仅在内部服务网格中暴露?
  6. 应用是否在关键点进行规范化/编码/过滤/拒绝?

    • 输出端是否有 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 全自动修复,必须人类全程介入:

  1. 核心业务逻辑漏洞:涉及资金、权限、计费的逻辑缺陷,AI 修复可能引入新的业务不一致。
  2. 高危可利用漏洞:RCE、SQL 注入(root 权限)、认证绕过等,修复方案必须在测试环境完整复测。
  3. 架构级缺陷:跨服务的信任边界问题、租户隔离缺陷,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.validateverify_finding 沙箱复现。

工程注意事项:

  1. 沙箱必须只与 staging 通信,禁止访问生产、禁止访问公网。
  2. PoC 代码以字符串形式注入容器,避免宿主机文件系统污染。
  3. verify_exploitability 只做粗筛,任何返回 True 的崩溃都需要人类用 GDB/WinDbg 复核。
  4. 生成 PoC 的 LLM 调用必须走独立账户,避免与生成 Lead 的调用共享上下文。

6. AI 让安全研究员"生疏"的风险

这是 The Hacker News 文章中被低估的一个议题。AI 不仅改变工作流,还在持续改变研究员的能力结构。

6.1 过度依赖的三个表现

表现 短期效应 长期风险
不再记忆细节 AI 即时回答所有问题 失去"看到代码即联想漏洞"的肌肉记忆
不再练习脚本编写 AI 生成第一版 失去调试、定制、扩展能力
不再构建心智模型 AI 解释所有代码路径 失去跨系统、跨层的整体判断能力

这三项能力的衰退是渐进且不可见的——研究员不会感到"我不会了",只会感到"我需要 AI 才能做"。当遇到 AI 无法处理的场景时,差距才会暴露。

6.2 为什么这很危险

四个具体原因:

  1. 深度漏洞发现依赖模式识别和技术回忆。AI 擅长的模式是"已知的已知",而真正的深度漏洞(如 Spectre、Log4Shell)来自"已知的未知"——研究员需要在没有先例的情况下识别异常。

  2. 最难的发现来自"一个领域的行为违反了另一个领域的假设"。例如,HTTP/2 的流复用在网络层是正常的,但在应用层可能导致请求走私;TLS 的会话复用在加密层是优化的,但在身份层可能导致认证绕过。这种跨领域的异常识别,AI 当前无法做到。

  3. 工具输出从来不够,需要理解信号的含义。Fuzzer 给出的崩溃只是信号,是否可利用需要研究员理解堆布局、CPU 流水线、内核缓解措施。AI 可以读 crash log,但无法判断"这个 crash 是否值得追下去"。

  4. 第一次尝试失败时,理解系统的人能适应,依赖工具的人会卡住。当 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(证明它)

证明什么?五件事:

  1. 证明漏洞存在——不是"代码看起来有",而是"在运行环境中确实有"。
  2. 证明攻击者可达——不是"理论上可达",而是"在当前部署配置下实际可达"。
  3. 证明影响——不是"CVSS 9.8",而是"攻击者实际能造成的具体损害"。
  4. 证明业务风险——不是"漏洞严重",而是"对资金、用户、合规的具体后果"。
  5. 证明修复有效——不是"代码改了",而是"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 漏洞挖掘最大的工程错误。