生成式 AI 正在把攻击者的代码分析和漏洞利用速度推向机器级别。面对被窃取的企业代码仓库,防守方如果仍依赖完全手工的源代码审查,往往很难在攻击者之前完成定位、验证和修复。
一种更可行的思路,是把大模型放进一个严格编排的安全分析流水线:让不同智能体分别负责代码侦察、威胁建模、入口发现、上下文补全、假设生成和结果验证,再由安全专家进行最终判断。Mandiant 分享的 Agentic Vulnerability Discovery Harness(AVDH)正是这种架构的一个实践案例。
从“让模型看代码”转向“让流程约束模型”
大模型擅长理解复杂代码和跨文件关系,但它也具有非确定性:同一段代码可能得到不同结论,模型还可能忽略权限、路由、配置或运行时条件。单次提问很难承担严肃的漏洞审查任务。
AVDH 的关键不只是使用了某个模型,而是建立了一个由程序控制的多阶段 Harness。每个阶段有明确输入、输出和质量门槛,智能体按照顺序推进,最终生成供人工审核的风险排序结果。
典型流程可以抽象为:
- 代码侦察与威胁建模:识别应用类型、核心组件、暴露面和不应纳入分析的目录。
- 入口发现:扫描 HTTP 路由、IPC 监听器及其他领域相关的攻击入口,并提取用户输入。
- 上下文补全:沿着函数调用、权限检查、清洗器和数据存储边界收集相关代码。
- 假设生成:分别从访问控制和数据流角度提出潜在漏洞假设。
- 假设验证:使用多个独立验证智能体交叉检查,再由合成智能体作出确认、推翻或拒绝的结论。
- 人工验证:通过动态测试和 Proof of Concept 验证可达性、可利用性以及是否存在补偿性控制。
这种结构把“模型自由发挥”限制在具体阶段内。模型仍然负责理解和推理,但程序负责调度、聚合、去重、风险分级和人工交接。
威胁模型必须成为第一道闸门
代码安全分析最容易犯的错误,是脱离应用实际运行方式讨论某个危险函数。一个管理员专用接口和一个普通用户可访问的接口,风险完全不同;一段从未执行的测试代码,也不应和生产路径获得相同优先级。
因此,流水线应先回答几个问题:
- 目标软件属于 Web、桌面、服务端还是其他领域?
- 哪些组件能被外部用户、低权限用户或内部服务触达?
- 身份认证和授权检查位于哪里?检查的是谁的身份?
- 哪些路由、IPC 监听器、消息消费者或任务入口接收用户控制的数据?
- 哪些目录是测试、构建产物、示例或第三方依赖,不应直接纳入分析?
- 关键组件之间如何连接,输入经过哪些清洗、转换和存储边界?
在 AVDH 的做法中,Explorer 智能体先建立软件全貌,再派发 Specialist Explorer 分析认证、授权、路由等领域,最后由 Threat Model Synthesis 智能体生成统一威胁模型。安全顾问在继续分析前检查文本和可视化结果,相当于给自动化流程加了一道审批门。
这道门很重要。威胁模型如果错了,后续分析即使找到了大量“危险代码”,也可能因为缺少可达性和业务上下文而产生大量误报;更严重的是,模型可能把真正重要的攻击路径排除在外。
控制流与数据流要分工分析
漏洞通常不是一个孤立函数造成的,而是入口、权限、调用链、数据变换和危险操作共同形成的结果。将所有任务交给一个通用智能体,会让上下文过于庞杂,也不利于定位漏检原因。
可以把分析拆成两个互补方向:
- 访问控制分析关注控制流:入口是否需要认证,权限是否检查,检查是否针对正确主体,敏感操作是否能被低权限用户调用。这类分析可以发现缺失授权、权限提升和 CSRF 等问题。
- 数据流分析关注输入如何移动:用户输入是否经过校验和清洗,是否跨越数据库、文件系统或命令执行边界,最终是否抵达危险 Sink。这类分析可以发现 SQL 注入、XSS、命令注入和路径遍历等问题。
上下文补全智能体负责把入口附近看似无关的代码找回来。例如,一个路由处理函数可能只调用了服务层方法,真正的权限判断位于更深的中间件,危险的字符串拼接则发生在另一个文件中。只看入口文件,无法判断完整攻击链。
一个可改造的最小流水线示例
下面是一个不依赖外部模型 SDK 的 Python 示例,用确定性的函数模拟多智能体编排。它展示了如何把阶段、质量门槛和人工交接写成可审计的程序。接入实际模型时,可以将各阶段函数替换为 Google ADK 或其他编排框架中的 Agent 调用,并保留输入输出契约。
运行前只需要保存为 avdh_demo.py,执行 python avdh_demo.py。示例不会扫描真实代码,也不会执行利用代码。
from dataclasses import dataclass
from typing import List
@dataclass
class Finding:
title: str
severity: str
evidence: str
status: str = "candidate"
def explore(repo: str) -> dict:
return {
"repo": repo,
"domain": "web application",
"in_scope": ["src/routes.py", "src/services.py"],
"excluded": ["tests/", "vendor/"],
"entry_points": ["POST /admin/export"],
}
def build_threat_model(recon: dict) -> dict:
return {
"domain": recon["domain"],
"entry_points": recon["entry_points"],
"assumptions": [
"The endpoint is reachable by an authenticated user.",
"Export authorization must be checked against the requesting user.",
],
}
def generate_hypotheses(model: dict) -> List[Finding]:
# In production, this stage would call access-control and data-flow agents.
return [
Finding(
title="Possible missing authorization on export endpoint",
severity="high",
evidence="POST /admin/export reaches export_data without a role check",
)
]
def validate(hypothesis: Finding, model: dict) -> Finding:
# Replace with independent validators and a synthesis agent.
if "authorization" in hypothesis.title.lower():
hypothesis.status = "confirmed"
else:
hypothesis.status = "rejected"
return hypothesis
def human_gate(findings: List[Finding]) -> List[Finding]:
# A real review must reproduce reachability and test compensating controls.
return [finding for finding in findings if finding.status == "confirmed"]
def main() -> None:
recon = explore("sample-repository")
threat_model = build_threat_model(recon)
print("Threat model:", threat_model)
candidates = generate_hypotheses(threat_model)
validated = [validate(item, threat_model) for item in candidates]
confirmed = human_gate(validated)
for finding in confirmed:
print(f"[{finding.severity.upper()}] {finding.title}")
print("Evidence:", finding.evidence)
print("Next step: reproduce safely in an isolated test environment")
if __name__ == "__main__":
main()
这个示例有三个值得保留的设计点。第一,威胁模型在假设生成前完成;第二,候选发现和确认结果分开保存,避免把模型的初步猜测直接当作漏洞;第三,人工闸门是显式阶段,而不是一句模糊的“请专家复核”。在真实系统中,还应为每个阶段记录模型版本、提示词版本、规则版本、输入文件范围和最终裁决。
高温验证与低温执行并不矛盾
漏洞假设生成和漏洞结论确认适合不同的模型配置。生成阶段的目标是扩大覆盖面,可以允许智能体提出更多可能性;验证阶段则需要独立视角,避免一个智能体的早期判断影响所有后续结论。
AVDH 的验证阶段会并行调度多个较高温度的 Validation agent,让它们从不同角度审查同一个假设,再由 Validation Synthesis agent 汇总证据。最终结果分为三类:
- Confirmed finding:假设具有充分证据,并通过独立验证。
- Disproven hypothesis:存在明确证据反驳漏洞成立。
- Rejected hypothesis:不符合威胁模型,或不满足漏洞定义。
这里的高温不是为了让输出更“有创意”,而是为了增加验证路径的多样性。实际部署时仍需通过基准测试确定温度、模型和并发度,不能把某个参数配置当成通用答案。
把专家经验做成可维护的规则系统
仅依赖人工复核可以降低误报,却不能充分解决漏报。要提高召回率,需要把安全顾问长期积累的经验注入整个流水线,而不是只写在某个大提示词里。
一种可维护的组织方式,是把规则分成三层:
- 软件领域规则:说明 Web、桌面、微服务等不同软件类型的常见攻击面和分析重点。
- 语言与框架规则:描述特定语言、路由框架、ORM、认证中间件和库的入口模式及特殊行为。
- 漏洞规则:定义某一类漏洞的发现方法、验证要求和风险评级标准。
语言和框架规则可以作用于整个流水线,帮助侦察、入口识别和上下文补全;漏洞规则则主要在后期使用,指导智能体如何验证 SQL 注入、命令注入、权限缺失等具体问题。
规则系统应当模块化、可版本化,并且参与基准测试。每次修改规则,都要知道它提升了哪些漏洞类型的召回率,又引入了多少误报。
用专有基准集衡量真实能力
公开漏洞数据集适合快速入门,但不一定适合作为唯一评测依据。现代模型可能在训练阶段接触过公开仓库,测试结果有可能反映记忆,而不是对新代码的推理能力。
可以这样实践:建立一组由安全人员人工注入并验证的合成代码库,覆盖不同语言、框架、软件架构和漏洞深度。每个漏洞都必须确认真实可达,并在隔离环境中动态验证。
评测流程至少需要处理三类问题:
- 漏报:基准中的真实漏洞是否被发现?
- 误报:没有对应真实问题的发现是否确实是误报?
- 重复发现:多个结果是否指向同一个根因?
对非确定性模型,单次运行的结果不足以说明能力。应在多个代码库、多个架构和多次运行上取平均,并让人工专家检查 Grading agent 的判断。与此同时,要防止提示词和规则对固定基准集过拟合,定期加入未公开的保留测试集。
适合落地的两层防御策略
这类 Harness 更适合点时、深度和目标明确的任务,例如:
- 被窃取代码仓库的事件响应调查
- 红队和渗透测试前的源代码分析
- 高风险应用上线前的定向审查
- 复杂漏洞链和潜在零日问题的主动发现
它不应被当作完全自动化的漏洞发布机器。真正的确认仍需要专家检查调用链、运行配置、权限边界和补偿性控制,并在隔离环境中复现攻击条件。没有动态验证的“高危”结果,最多只能称为待验证假设。
在持续防御场景中,可以将点时深度分析和持续扫描结合:持续扫描负责保持开发生命周期中的可见性,Agentic Harness 负责针对关键资产和复杂攻击链进行集中分析。两者的结果应统一进入漏洞管理流程,避免同一问题在不同工具中重复计数。
落地检查清单
- 明确威胁模型,并设置人工审批门。
- 为侦察、入口发现、数据流、访问控制和验证定义独立输出契约。
- 使用上下文补全追踪跨文件、跨函数和跨组件的数据流。
- 将候选假设、确认发现、推翻结论和拒绝结果分开存储。
- 把语言、框架和漏洞知识做成可版本化规则。
- 对每个确认发现执行安全的动态复现和 PoC 验证。
- 使用专有、可达、可利用的基准集持续评测召回率和误报率。
- 记录模型、提示词、规则、代码快照和裁决过程,保证结果可审计。
- 将自动化定位能力用于释放专家时间,而不是取消专家责任。
防守方要追上对抗性 AI,关键不是寻找一个能够独立完成安全审查的模型,而是构建一条能被验证、能被复现、能吸收专家经验的工程流水线。模型负责扩大分析范围,Harness 负责约束过程,安全专家负责确认现实世界中的攻击成立条件。三者结合,才可能把代码可见性真正转化为可执行的防御速度。