作者:Dan Jones, Alexandra Godoi, Grant Bourzikas
时间:2026年06月18日
原文:https://blog.cloudflare.com/build-your-own-vulnerability-harness/
几周前,我们发布了 Project Glasswing 的初步发现,观察当你把前沿安全模型指向企业级代码库时,会发生什么。我们也探讨了自身防御体系如何演进,以保护基础设施和客户免受前沿 AI 带来的威胁。此后,AI 生态仍在快速变化。那些围绕单一模型深度构建工作流的开发者,已经切身感受到:当这个模型不再可用,或被能力更强的新模型取代时,系统会面临怎样的冲击。这些市场变化进一步印证了我们的核心判断:无论某一天领跑的是哪一个底层模型,智能体工作流的未来,都不会停留在孤立的模型、提示词,或单次 agent 会话之中。
要把一个局部安全 skill 推进为持续运行、覆盖整组代码仓库的扫描流水线,就需要一种架构:在这个架构中,模型被视为可以替换的组件。依赖单一模型,天然会限制防御覆盖面,因为同一个系统往往会用同一套视角审视代码路径。为应对这一问题,模型应当被频繁替换,并进行交叉测试。通过在流水线不同环节使用不同模型,例如用一个模型做初步发现,再用完全不同的模型做验证,我们可以让漏洞由不同逻辑体系进行交叉核验。进一步说,真正适用于企业级场景的 harness,不能只停留在单个代码仓库内,而应能够跨仓库依赖追踪漏洞,最终把成千上万条原始候选项,过滤成可信、已分诊、可执行的修复队列。
本文将从实践角度出发,介绍如何构建这样一个与具体模型解耦的中间层,重点讨论我们如何管理状态控制、消除误报,并在大规模场景下协调端到端的漏洞分诊流程。
先回应两个质疑
上一篇文章解释了为什么通用 coding agent 难以胜任这项工作。核心问题在于,agent 通常一次只能维持一个假设;在真实代码仓库中只覆盖很小一部分内容后,上下文窗口就会被填满;随后又会在上下文压缩过程中丢失信息。在继续展开之前,我们想先回应两个可能的问题。
“为什么不用 subagents,而要做一个 harness?”Subagents 确实有用,也是一个不错的起点。但安全分析需要的是数百个相互独立的调查任务:它们要能跨多次运行持续存在,不共享同一个上下文窗口,并且后续可以重新界定范围、相互引用。它需要持久化、去重、可恢复执行,并最终支持整组代码仓库的依赖关系追踪。这是一个编排问题,不是把提示词写得更好就能解决的。
“这篇文章是不是只是在给前沿模型做广告?”不是。我们的方法以 harness 为中心,模型只是其中可替换的一层。在漏洞发现方面,我们会使用当前最适合任务需求的前沿模型。把不同模型指向同一个目标时,它们往往会发现不同类型、不同部分的漏洞。真正能够沉淀下来的,是 harness 本身。如果你要构建自己的系统,就应当从第一天起把它设计成模型无关的架构。这样,你才能不受约束地选择最合适的模型。
一切从一个 skill 开始
我们一开始做的是一个大约 450 行的安全审计 skill,把它跑在单个代码仓库上,然后不断调整 prompts,直到它能够找出真实漏洞。后来,我们在此基础上加入了编排能力,它逐渐成为整个系统的管道层。真正有价值的部分,仍然在 prompts 本身。直到今天,我们的 prompts 仍几乎完整保留着最初那个 skill 里的攻击者场景、漏洞类别和反模式检测逻辑。
这个 skill 被设计成在一次会话中完成一轮 7 阶段审计:
三个并行的 research agents 先做侦察,并写出一份
architecture.md。每一种攻击类别对应一个 Hunter agent,它的任务是尝试攻破代码,而非做常规审查。
对抗性 validators 会尝试推翻每一个发现。
留存下来的发现,会被写成一份人类可读的漏洞报告。
这些发现也会按照 schema 输出为
findings.json,再由机制检查验证这个文件。最后,一个全新的 agent 会基于源代码,独立重新验证每一项发现。
通过重新验证的留存发现,会被提交到 ingest API。
最初这个 skill,几乎可以直接映射到后来的 harness:
这个 skill 能跑起来,但它也很快暴露了自己的边界。从覆盖率指标看,单次运行大约只能发现多次运行累计可发现漏洞的一半。以我们的经验,它找到的那些问题也更偏向简单、直观、不那么隐蔽的漏洞。当你的流程基本变成“跑十遍,然后人工 diff 结果”时,就该认真考虑引入一个真正的 harness 了。
在运行和调优这个 skill 的过程中,我们撞上了三堵墙。
第一是上下文耗尽。运行一个小时后,上下文窗口会被填满,模型开始吞掉自己的记忆,瞬间忘掉它花了整个上午才追踪到的漏洞。我们打破这个瓶颈的方式,是把状态完全外置,把 LLM 当作无状态的计算引擎来使用。
第二是持久化。一次中途崩溃,就意味着从头再来。因为一次 AI rate limit 错误或网络连接抖动而损失几个小时工作,是一种代价很高的架构教训。
第三是跨仓库推理。单仓库会话完全看不到不同应用和被调用组件之间的关系;当你开始检查组件接口处的问题时,浮现出来的漏洞数量很可能比想象中更多。
建议是:一个真实但最小化的 harness,只需要包含 Recon、Hunt 和 Validate 三个阶段,并把它们保存在数据库里;同时再配一个独立 Validator,它不能提交自己的发现。在你还没有多个真正重要的代码仓库之前,可以完全跳过跨仓库追踪。在你尚未被噪声淹没之前,也不必急着做一个专门的 Deduplication agent。先在开发环境里从一个 skill 开始,把 prompts 调到足够好;只有当缺少下一层架构已经明确拖慢你时,再去建设下一阶段。
把 skill 固化成流水线
这个领域里,大多数 AI 安全文章讨论的都是单个代码仓库,或者经过整理的基准测试。把这套方法跑在整组代码仓库上,并且做跨仓库追踪,我们还没有看到太多公开经验。我们的代码库横跨大量语言,包括 Rust、Go、C、Lua、TypeScript 和 Python;除此之外,还有各种配置管理系统、静态配置文件,以及许多额外上下文。因此,我们必须搭出一套真正适合自己的新系统。
从最初那次 slash command 运行,到一个能够覆盖 128 个不同代码仓库、自动发现并追问相关依赖关系的 fleet scanner,大约花了六周时间。固化过程本身大多是机械性的:我们把 skill 的每一个阶段提升成独立 agent,在后面接上数据库,在前面放上 orchestrator。两者之间的映射几乎是一一对应的。
整组代码仓库都运行在同一个统一 harness 上,不需要针对不同语言单独调优,并且能够追踪仓库之间的依赖关系。把语法层面的理解交给模型,使系统获得了语言无关性;但真正的差异点,在于它能追踪不同仓库之间的依赖。harness 本身并不关心眼前是 C 语言指针,还是 TypeScript 文件;它关注的是更高层的安全编排逻辑。这让我们不必为每一种语言编写定制解析器,也能扩展到数百个不同代码库。
两阶段漏洞研究工作流
我们的整个漏洞研究工作流,建立在一个两阶段运营框架上:Vulnerability Discovery Harness,简称 VDH;以及 Vulnerability Validation System,简称 VVS。
VDH 是我们的发现引擎,会主动扫描代码库,找出潜在安全问题。漏洞进入 VVS 之后,会依次经过 Deduplication、Judgment 和最终 Fixing 等阶段。VVS 可以接收来自多个 harness 的输入,后文会进一步展开。
我们在 VDH 中使用一个模型,但在 VVS 中使用完全不同的另一个模型,所以两个模型实际上会相互复核。这样做有明显的安全价值:让模型 B,也就是 VVS,去判断模型 A,也就是 VDH 的输出,意味着每个发现都会被另一套完全不同的逻辑权重和训练数据重新评估。它相当于一个不带偏见的对抗性第三方,唯一任务就是毫不留情地压力测试模型 A 的假设。
从运营角度看,把模型供应商当作可以替换的基础资源,也会带来好处。模型供应商可能会随着时间调整 temperature、caching 和 inference effort budget,甚至在同一个模型版本内也会这样做。与其构建一个依赖模型长期稳定表现的系统,我们更愿意让 harness 能够吸收下游波动,而不至于因此中断。
第一阶段:Vulnerability Discovery Harness(VDH)
上一篇文章已经讲过每个 agent 和阶段的作用,所以这里重点讨论它没有展开的部分:阶段之间的胶水,以及决定整套系统能否真正跑起来的几个细节。
表 1:Vulnerability Discovery Harness(VDH)
第四到第八阶段会作为一个连续的生产者-消费者循环运行。随着初始 hunt 推进,Gapfill、Feedback 和 Trace agents 会生成新任务;Dedup 会把重叠发现重新折叠合并,循环中的其他部分则持续消费队列。这保证了即便某个漏洞是在周期较晚阶段才被发现,它仍然会在同一次运行中完成验证、报告,并与其他代码进行比对,确认是否存在同类问题。
以这种方式拆分流水线,可以确保严格的上下文控制。一旦填满上下文窗口,模型就会开始产生幻觉。我们让每个 agent 的任务都高度聚焦,把上下文使用量控制在总窗口的 25% 以下。那种天真地“读取所有文件”的做法,每一次都会突破这个限制。
有一件事曾让我们踩坑:持久化需要先于并行化来考虑。你不会想因为一次意料之外的错误,就丢掉一个运行了五小时的任务。每个阶段都会写入同一个 SQLite 数据库,并用 (run_id, repo, stage) 作为 key。任何阶段都可以恢复、重试,或者在后续运行中被拉回来继续使用,而不必重做已经完成的工作。findings 会在产生时流式写入和保存,所以一次崩溃最多只会损失正在执行的那个任务,不会影响其他结果。
还有一个容易踩的坑:有时,临时 API 错误不会以代码异常形式抛出,而是作为文本出现在
(200 OK)的响应流里。对 orchestrator 来说,这看起来和一个正常完成的任务完全一样。因此,你必须显式分类响应文本,不能只相信异常类型,否则最后会把空运行记录成成功。
动态威胁建模
在 Recon 阶段,威胁模型不是预先交给 agent 的;它要由 agent 自己写出来。除了大约十种内置攻击类别,包括多种形式的注入、内存破坏、协议解析、计时侧信道等之外,Recon agent 还可以现场发明面向特定代码仓库的攻击类别,并为每一类配套自己的方法论。它会写出一套专门针对该代码库的定制分类体系,用来更精确地约束 Hunter agents 的范围。
只读源代码,不足以理解代码在压力下会如何表现,尤其是 C 和其他底层语言中那些隐蔽的未定义行为缺陷。Hunter agents 会越过代码阅读阶段,进入主动执行。它们会编译片段,构建小型版本,然后攻击它们。质量提升最大的一步,是给 Hunters 一个基于 unshare 构建的 sandbox,让它们可以让二进制程序崩溃。
一个建议:如果 harness 本身运行在 Docker 里,这个 sandbox 需要设置
seccomp=unconfined和apparmor=unconfined,否则它会静默启动失败。对于像我们这样不精通嵌套容器化的人来说,这是一行配置就能省下一整天排查时间的问题。
Micro-forks 与 wishlist
在核心流水线阶段之外,我们加入了两个专门机制,让 Hunters 拥有更高自主性。它们可以调整自己的关注点,也可以请求外部资源,同时不会让正在进行的分析跑偏。
Sibling Forking:如果一个 Hunter agent 碰到了一条有意思、但超出当前范围的代码路径,这个机制可以避免它偏离主线。它会通过一次 tool call,带着精确的结构化 seed,fork 出一个 sibling agent。从整个 fleet 看,这类任务大约占 9%;不过这个比例高度依赖模型,不同模型之间可以从接近 0 到大约五分之一不等。
Wishlist:当 agent 需要一个自己没有的工具时,通常是 Validator 想确认一个 Proof of Concept(PoC),或者 Hunter 想构建某个东西,例如特定 build environment、VM 或某些生产配置文件,它会写入一个中央 wishlist。它会提供足够上下文,使系统能在人工提供依赖之后,自动重新运行那个精确任务。有些情况还可以部分自愈:如果容器需要带着某些改动重新构建,一个通用 coding harness 可以在运行结束后监控日志,并自动完成这件事。
自从加入 wishlist 以来,它已经在 128 个代码仓库中被写入 25,472 次,也是 agents 与我们反向沟通的主要方式。我们写这篇文章时,就刚好收到一条:“我需要一台 FreeBSD VM,才能端到端确认这个 PoC。”
整组代码仓库的跨仓库追踪
初步清理之后,Tracer agent 会检查不同软件组件之间是如何连接的。它寻找的是一条特定路径:潜在攻击者能否从外部把有害输入送到系统中的脆弱部分?如果答案是肯定的,Tracer agent 会自动在 consumer repository 中生成新的 hunt 任务。要做到这一点,你需要一个统一的跨仓库 symbol index,以及一张准确的 dependency graph。这样,你才能发现标准单仓库扫描会漏掉的深层、系统性缺陷。
把我们的 harness 跑在整组代码仓库上之后,有两个经验只有在规模化之后才浮现出来。
第一,去重本身就是一个问题,大到需要自己的 agents。当你只扫描少数几个代码仓库时,可以人工看出哪些漏洞彼此重叠。但在这里,简单的字符串匹配或文件路径检查救不了你。判断两个复杂逻辑缺陷是不是同一个根因问题,听起来很简单,实际并不简单。它需要大量认知推理,所以我们不得不部署专门的 Dedup agents 来清理噪声,并为它们配套自己的启发式规则和工作量削减方法。
第二,不要太早接入静态分析。我们把 Semgrep 完整接进了系统,但在一个月的运行中,Hunters 调用它的次数是 0。它们更愿意阅读和运行代码。相比之下,wishlist 是整个系统中使用最多的工具。值得关注的是 agents 实际会伸手去拿什么,而不是你以为它们会需要什么。
让漏洞发现变得可信
Agent 会编辑源代码,让自己的 exploit 成功运行,然后兴高采烈地报告它刚刚亲手制造出来的漏洞。它会写一个证明完全同义反复的测试,比如“exec() 会执行东西,所以这是严重漏洞”。或者,它会构建一个能跑通但什么也证明不了的 exploit,因为背后的威胁模型本身就是错的。如果你的 harness 不主动对抗这些问题,你搭出来的只是一个更快生产垃圾的系统。
Hunter 在提交任何东西之前,必须先说明威胁模型。它必须精确定义攻击者是谁,以及这个漏洞跨越了什么边界,或者打破了什么假设。输出 schema 的顺序会强制执行这一要求。这个要求可以消除那些空洞 findings,比如“如果用户拥有数据库写权限,那么他可以写数据库”这一类。
每一个确认后的 finding,都会附带一个以测试形式写成的 PoC,并且这个测试必须运行在原始、未被修改的代码库上。这样可以防止 agent 编辑源文件,强行让 exploit 命中。如果没有可运行的 PoC,我们就把这个 finding 当成假的。实际操作中,这可能是一个 Hunter 编译了一段 30 行的解析循环,在开启内存保护的情况下运行它,并证明错误的读取步长来自某个栈地址,而不是预期的消息体。你可以自己重新运行它。进一步说,每一个确认后的 finding 还必须附带一个 proposed patch。最终进入我们审查队列的,是一个已经验证的漏洞、一个可运行测试,以及一个可工作的 git diff,而不是对某个问题的模糊文字描述。
在一条 exploit path 留存下来之前,确定性代码,也就是普通代码而不是另一个模型,会机制验证被引用的文件和路径是否真实存在,并确认 patch 和 test 都能正确解析。这个 Validator 不能记录自己的 findings;它唯一的工作,就是尽可能推翻 Hunter 的理论。如果允许 Hunter 批改自己的作业,它会自信地验证自己输出的一切。
我们不会声称这个系统有某个 false-negative rate。代码库里并不存在一套标注了所有真实漏洞的数据集,因此任何召回率数字都完全是猜测。我们可以观察的是,重复运行是否还在不断发现新漏洞,答案是会;以及跨运行的覆盖率是否仍在增长。这些都只是代理指标,因为你无法确切知道单个代码库里到底有多少漏洞,但它已经足够用来衡量效果。
第二阶段:Vulnerability Validation System(VVS)
从 harness 输出一个 finding,只是分诊流程的起点。所有发现都会进入同一个共享 VVS;目前,这个系统一共覆盖 145 个代码仓库,保存了 13,841 条 findings。分诊这个规模的结果,本身就是一个庞大的工程问题,它和 hunting 一样重要。这个分诊引擎使用的模型不同于 harness,并被拆分成三个不同任务。
表 2:Vulnerability Validation System(VVS)
去重
如果用 LLM 把每一个 finding 和其他所有 finding 两两比较,规模会按 O(N^2) 增长,一旦放到真实规模就会彻底崩掉。为了让模型避开关键路径,确定性代码会基于结构化数据构建倒排索引,包括被触及的文件和函数、信任边界、rare tokens 等,从中生成一份真正值得比较的短候选列表。只有到这一步,agent 才会查看这份短列表,判断一个修复是否可以同时关闭其中几项。稳定的跨运行 key 可以确保被重新发现的漏洞会重新打开已有记录,而不是生成新记录。
上下文判断
Judgment 是对留存结果进行的第二轮独立检查。Agent 会重新核验最新信息,从部署、环境和配置上下文中拉取资料,判断这条代码路径在生产环境中是否可达,并识别 repo owner。这个过程会把“当前可利用”的问题,同“真实存在但暂时潜伏”的问题,以及“真实存在但归属组件错误”的问题区分开来。它的作用,是把一堆混乱 findings 转入一个由风险驱动的编排工作流。
自动修复
Fixer 会接收 proposed patch 和 unit tests,把它们改写成符合该仓库风格的形式,应用 diff,并运行定向测试。最理想、也是唯一可以自动清理的情况,是测试出现清晰的 fail→pass 翻转;如果补丁后的测试失败,commit 就会被阻止。Fixer 绝不会自行合并代码,必须由人类 review 这个分支。这道 gate 是不可协商的人类在环保护措施,也让变更管理合规所需的留痕保持清晰、不可篡改。如果放任模型自由打补丁,它会很乐意修掉一个安全漏洞,同时悄悄破坏某个无关功能,或者引入几十个新问题。
在三个分诊任务中,每个 agent 都被限制在一个非常窄的任务里,外面包着确定性的状态管理代码;没有任何东西会在未经人类确认 dry run 的情况下写入生产。虽然这条流水线把工程瓶颈从“发现漏洞”转移到了“审查并落地修复”,但 Fixer 仍然是整个系统中最年轻、最慢的一部分。
成本结构
让数百个 agents 在整组代码仓库上运行并不便宜,但至少成本形态是可预测的。几乎所有计算预算都会直接花在 hunt 阶段。这让 Gapfill 成为我们调节成本和覆盖率的杠杆,因为每多跑一轮,成本大约只有初始 hunt 的一半。
由于不同代码仓库的成本差异非常大,我们按 repo 做预算,而不是按 run 做预算。我们会对每个代码仓库设置严格的任务上限,并启动一个规模在 50 到 200 个 workers 之间的 worker pool。这样,你可以把钱花在真正有发现的仓库上,而不是浪费在没有产出的仓库上。
这也是为什么对我们来说,大规模扫描是周期性的 backlog sweep,而不是每个 PR 都跑的检查。一个复杂代码仓库的完整扫描可能需要数小时;最糟的一次运行用了刚刚超过 14 小时。对于 per-PR 检查,成本更低、规模更小的 harness 才是合适工具。
如何判断它真的有效
我们衡量系统有效性的方式,是看自动化流水线能否高效地把有意制造出来的工程噪声,过滤成高质量、可执行的 findings。由于我们会有意把 Hunters 调成过度报告模式,让它们尽量报出那些可能被串联进更大攻击链的细微 primitives,所以真正的成功指标,是在这些原始数据到达人类面前之前,我们能多大幅度地把这座数据山压缩下去。
为衡量这一点,我们会持续追踪有多少 raw findings 能够通过各个验证阶段。得益于 Recon 阶段更好的上下文注入,我们的初始验证拒绝率从 40% 降到了 11%;与此同时,高完整度 findings 的占比从 35% 提升到 58%(对应约 12,057 条历史 findings)。
下面是截至这篇文章写作时,从原始候选项到可执行 findings 的全生命周期拆解。
Vulnerability Discovery Harness(VDH):
Raw candidates:独立验证之前,discovery harness 输出的全部内容。
Needs repro:看起来可信,但需要人工复现后才能确认的 findings。
Rejected at validation:validator 推翻了威胁模型、exploit path、受影响代码或证据。
Duplicates:被折叠到同一 harness 生成的另一条 finding 上的候选项。
Survived validation:通过独立验证 gate,并进入 VVS 的 findings。
Bugs that went elsewhere:被有意路由到这条流程之外的 findings。
Vulnerability Validation System(VVS):
Another vulnerability harness:输入同一个验证系统的其他自动化来源。
Total bugs in system:ingest 之后形成的合并池。
Duplicates:dedup 阶段识别出的、已由另一条 canonical finding 或 ticket 覆盖的 findings。
Wrong repo / other / not a risk:噪声桶,包括归属仓库错误、纵深防御问题,或潜在但暂不构成风险的问题。
Bugs sent to teams:整理完成、可以交给工程团队修复的干净 findings。
Judged Internet-exploitable:现实攻击者可以在生产环境触发的高优先级 findings。
Not judged Internet-exploitable:优先级较低但仍可执行的 bugs,包括生产问题、依赖风险或配置错误。
Final severity split:用于给工程团队分配优先级的最终严重性分类。
harness 的核心指标并非某个猜测出来的召回率,而是尽可能让真实人类面前的未确认 findings 数量接近于零。整个架构需要成为一个持续压缩噪声的过滤漏斗。
在 VDH 生成的 20,799 条 raw candidates 中,最终只有大约 12,057 条通过了验证。
这些 findings 被推入 VVS,并与来自另一个 harness 的 findings 汇合后,中央池达到 13,841 条。
Dedup agent 把其中 5,442 条作为重复项折叠掉。
另外 1,154 条被路由到“wrong-repo”或“low-risk”队列,并在适当情况下重新回收到系统中。
最终,留下 7,245 条可执行 findings,交给工程团队处理。
传统合规规则通常完全基于静态 CVSS 分数,规定任意化的修复窗口,例如“所有 High 必须在 30 天内修复”。我们的 contextual judgment 层会把这个合规勾选项,转化成真正的风险管理。
这套架构能够把 findings 追溯到源头,这意味着修复一个根因,可以解决一整组 findings,而不是逐个打补丁。VDH 的系统性能也会通过另一种方式衡量:把代码仓库拆成(area × attack-class)单元,然后迭代运行 Gapfill agent,直到它不再产生 findings。每当我们更新底层 prompt 时,都会用一个留出的 repository 进行测试,看总覆盖单元数量是否真的发生变化。
harness 还接入了自动化健康信号,用来在流水线早期发现系统故障。如果一次 hunt 结束得异常快,而且没有派生 sub-hunts 或 gap tasks,通常说明某个依赖崩溃了,而不是代码库真的干净。为解决这个问题,系统会把任何以零 findings 结束的 Hunter agent 标记为 “shallow”,并立即重新排队运行。
最后,系统的稳健性还来自前面提到的独立分诊阶段。通过使用不同模型和不同逻辑权重,对所有提交进行重新判断,我们可以确保发现过程之外存在一层不带偏见、对抗性的验证。这一信任层与具体用于 discovery 的模型解耦,因此无论当前使用的是哪一个模型,它都能持续存在。
我们的北极星指标:衡量真实世界的推进速度
每个代码库都有些不同。为了说明这套系统在真实世界里到底如何运行,我们基于一次标准仓库运行,整理了一组更接近现实的基准。需要注意的是,这代表的是单个代码仓库的一次扫描;随着持续运行的整组代码仓库循环不断去重、过滤和回收 findings,长期候选项总量大约会减少 65%。
通过自动化打补丁节省工程时间:相比静态基线,我们更关注流水线的技术吞吐量、处理速度,以及它消除人工分诊瓶颈的能力。
Initial Validation Cut:对于一个标准代码仓库(约 3 万行代码),系统会产生 100 条初始 findings;一次完整运行需要 3 到 4 小时,并且全程保持高度聚焦的上下文窗口。
Compression:Deduplication 和 Contextual Judgment 层会并行处理这些候选项。3 小时内,系统会把这批 findings 从约 100 条 raw candidates 压缩和精炼为 80 个彼此不同的高可信漏洞。
Remediation:自动化 Fixer 会以平均每个漏洞 5 分钟的速度处理这 80 个不同漏洞。总体来看,系统可以在大约 14 小时内完成发现、验证、去重,并打开可工作的 pull requests。
缩短关键缺陷的 mean-time-to-resolve:当然,你不能一次性把 80 个 patches 全部倒进生产环境,否则很容易把系统弄坏。为了保证部署安全,我们的系统采用分层 rollout。
Critical Exposure Containment:系统会先隔离 critical、high 和 exploitable 漏洞,平均大约是 80 个中的 10 个。我们会让这些问题进入快速人工审查,并纳入发布周期,使它们在 5 天内完成生产环境修复。
Incremental Hardening:剩下的潜在风险、轻微配置异常和较低优先级漏洞,会在 15 到 20 天窗口内逐步进入生产环境,以保证平台稳定性。
我们如何处理这些补丁
这些 findings 来自一个隔离、受限的研究实验,目的是对我们的代码进行压力测试。它们并不代表当前生产环境中仍然存在活跃、未修复的漏洞。
由于 harness 会在测试环境中持续运行,等你读到这里时,这些具体数字已经完全过期。流水线发现的每一个漏洞,都附带了一个可运行测试用例,用来演示问题,同时也带有一个草拟 patch。我们的安全团队正在系统化处理这些报告,并应用必要修复。这意味着你每天使用的 Cloudflare 产品,已经在主动针对这些攻击向量进行加固。
随这篇文章一起,我们也发布了最初用于开发 harness 的 skill。发布前我们对它做了一点清理,让它更容易理解和集成,但 skill 本身基本保持不变。希望 harness 本身也会很快发布。它可以成为你构建自己的 vulnerability harness、自己的 skill,或任何最适合你需求的系统的起点:github.com/cloudflare/security-audit-skill
如果你的团队也在解决类似问题,并希望交流经验,可以通过 [email protected] 联系我们。
所有这些都还没有完成。我们一直在改系统,它离一门完美科学还很远。但现在,原始候选 findings 已经变得便宜,真正值得做的工作,是把它们转化成可靠、可验证的代码修复。
构建自己的 harness,意味着接受 AI 模型本身是易变的,但你的编排层不必如此。通过把安全逻辑从任何单一供应商中解耦出来,强制引入对抗性验证,并自动化你的分诊流水线,你就可以把一座由 LLM 噪声构成的大山,转化为一个可靠的、覆盖整组代码仓库的防御引擎。







