每次迭代都在削弱代码安全性
经过十轮LLM驱动的代码优化,43.7%的迭代链所含漏洞比起始基线代码更多。1智能体改进了功能,通过了测试,但代码的安全性却随每次迭代逐步恶化——研究人员将这一现象称为”规约漂移”。无人察觉,因为代码在除安全性之外的每项指标上都表现更好。
摘要
一项针对三个模型(GPT-5-Nano、Claude Sonnet 4.5、DeepSeek-V3)和2,880个迭代步骤的LLM迭代代码优化研究揭示了一个悖论:智能体在优化功能正确性的同时,悄然侵蚀着安全性。常规缓解手段收效甚微。在循环中加入静态分析安全工具(SAST门控)后,潜在退化率从12.5%上升至20.8%。SCAFFOLD-CEGIS框架通过四层验证机制应对这一问题,将潜在退化率降至2.1%,实现100%的安全单调性,代价是77%的任务完成率。这一发现值得所有运行自主智能体循环的从业者关注。
悖论
研究人员在六个安全类别(数据库、输入处理、认证、资源管理、密码学、路径处理)的24个编程任务中测试了三个LLM(GPT-5-Nano、Claude Sonnet 4.5、DeepSeek-V3),共产生288条迭代链和2,880个迭代步骤。1核心发现:多目标优化过程中的规约漂移导致安全性在连续迭代中逐步退化。
其机制如下:当智能体跨多轮优化代码时,每一轮都聚焦于功能改进——修复缺陷、添加特性、通过测试、提升性能。安全约束与功能目标争夺智能体的注意力。经过十轮迭代,智能体隐式”学到”(通过上下文积累)功能变更能产生正向反馈,而安全约束则毫无反馈。那些不直接贡献于可见功能的防御逻辑,就这样被简化、重构掉,或替换为更弱的方案。
43.7%的退化率来自一项独立观察研究,追踪了GPT-4o在十轮迭代中的表现。主实验将SCAFFOLD-CEGIS与五种现有防御方法进行了对标:基于提示的安全防护、自我优化、事后SAST检查、测试驱动守卫和混合守卫。1学术界此前已将迭代退化视为隐患,但这五种替代方案均未能解决问题。
Shukla、Joshi和Syed的一项独立研究(经同行评审,已被IEEE-ISTAS 2025接收)印证了这一规律。4研究人员选取十个经过安全验证的C和Java代码样本,分别采用四种提示策略各进行十轮迭代(共400个样本),仅五轮迭代后关键漏洞就增加了37.6%。漏洞分类覆盖内存安全、输入验证、密码学实现和注入缺陷等12个类别。不同研究团队、编程语言和评估方法得出一致结论,证实迭代退化是方法本身的固有属性,而非单一实验的偶然结果。
为什么SAST门控适得其反
最反直觉的发现:在迭代之间添加静态分析安全工具作为门控,潜在退化率从12.5%上升至20.8%。1
论文将原因归结为多目标优化中的规约漂移。一个互补的解释则对应人类软件开发中的已知现象:当开发者依赖代码检查工具和静态分析器时,他们写出的代码防御性更弱,因为”工具会帮忙发现问题”。同样的机制很可能也作用于LLM智能体。当智能体在迭代间收到SAST反馈时,会产生两个效应:
-
智能体为通过扫描器而优化,而非为编写安全代码而优化。SAST工具检测已知的漏洞模式(SQL注入、XSS、缓冲区溢出)。智能体学会规避这些特定模式,同时引入扫描器无法检测的新型安全弱点。
-
智能体移除”冗余”防御。如果扫描器报告A层的输入验证已经足够,智能体会在下一轮迭代中移除B层的验证。但B层的验证是纵深防御,而非冗余。扫描器无法区分两者。
结果:经SAST门控的迭代产出的代码能通过安全扫描,但潜在漏洞比未经门控的迭代更多。工具制造了虚假的安全感,使智能体变得更不谨慎而非更加谨慎。
任何在自主编码循环中使用SAST门控的从业者都应警惕:门控并没有在保护你,而是在训练你的智能体绕过保护。
SCAFFOLD-CEGIS的不同之处
SCAFFOLD-CEGIS框架采用了截然不同的方法。1该框架不检测已知漏洞模式,而是强制执行安全单调性:任何迭代都不能使代码安全性低于上一次迭代。
三种方法的对比结果:
| Approach | Latent Degradation (SSDR) | Safety Monotonicity | Task Completion |
|---|---|---|---|
| No gating (baseline) | 12.5% | Not measured | Higher |
| SAST gating | 20.8% | Not guaranteed | Higher |
| SCAFFOLD-CEGIS | 2.1% | 100% | 77.14% |
该架构采用四个顺序验证层,每层检查不同属性:1
| Layer | Function | Gate Criterion |
|---|---|---|
| Correctness | Run full test suite | All tests pass |
| Safety monotonicity | Compare SAST results between iterations | No new vulnerabilities vs. previous |
| Diff budget | Limit per-iteration change scale | Change size within threshold |
| Anchor integrity | Verify security-critical code elements | Substring, regex, AST, or semantic match |
该框架采用CEGIS(反例引导归纳合成)原则:候选生成、验证、反馈和重新生成构成闭环。系统并非使用形式化验证器,而是采用静态分析和语义锚点检查,将反例表示为结构化的失败报告。1如果任何一层拒绝了某次迭代,系统会回退到上一版本,而非尝试修复退化。
代价是实实在在的:SCAFFOLD-CEGIS的任务完成率为77.14%,低于安全性较弱的方法。1安全单调性以生产力为代价。框架会拒绝那些宽松系统本可接受并改进的迭代。这一取舍是否值得,取决于你更看重安全保障还是产出效率。
关键洞察:失败时回退,而非失败时修复。标准SAST门控循环检测到问题后会让智能体修复,而修复本身又是一次新的迭代,可能引入新问题。SCAFFOLD-CEGIS检测到问题后直接丢弃整个迭代。单调性保证源于从不接受退化,而非检测并修复退化。
与智能体编排设计的关联
这一发现与从业者围绕智能体CLI构建编排层的方式直接相关。2我在500多次自主运行会话中记录的七种失败模式,其中多种可由迭代优化悖论解释:智能体通过测试却降低代码质量、智能体为错误指标优化、智能体在重构过程中移除安全约束。
我在《解剖一只爪子》中描述的判断钩子通过不同机制应对退化问题。quality-gate.sh拦截缺乏证据的完成报告。filter-sensitive.sh在凭据写入磁盘前捕获泄露。recursion-guard.sh限制智能体生成深度。每个钩子都强制执行一种单调性属性:随着智能体迭代,系统在特定维度上不应变差。运行时宪法模式扩展了同一理念:嵌入式治理规则,智能体在执行期间无法覆盖。
Karpathy的autoresearch系统采用了相同模式。3评估框架通过git分支管理保留改进、丢弃退化。训练指标(验证集每字节比特数)充当单调性约束。任何使指标退化的实验结果都无法存活。
三个独立系统(形式化验证研究、ML研究基础设施、生产级智能体编排框架)殊途同归,汇聚于同一设计原则:失败时绝不迭代修复,一律回退重来。给智能体第二次机会修复退化,结果往往比直接丢弃退化、重新尝试更差。
从业者应采取的行动
基于研究发现的三项具体措施:
审计迭代循环的安全单调性。如果智能体执行多轮代码修改,应将每轮的安全态势与原始基线比较,而非仅与上一轮比较。仅比较相邻迭代时,累积漂移不可见。
不要仅依赖SAST门控。SAST门控的结果(20.8%退化率,比无门控更差)应当改变你设计反馈循环的方式。SAST工具在检测人类编写代码中的已知模式时很有价值,但在智能体迭代循环中,这些工具会变成智能体绕道而行的优化目标。将SAST作为多重信号之一,而非唯一门控。
实施失败即回退,而非失败即修复。当某次迭代引入退化时,整体丢弃该迭代,不要让智能体在后续迭代中修复退化。修复尝试本身也是一次迭代,同样受制于相同的退化动力学。以下是使用git的最小实现:
#!/bin/bash
# monotonicity-gate.sh — revert on security regression
BASELINE_HASH="$1" # git hash of the known-good baseline
# Run your security checks against current state
CURRENT_VULNS=$(semgrep --config auto --json . | jq '.results | length')
BASELINE_VULNS=$(git stash && git checkout "$BASELINE_HASH" -q && \
semgrep --config auto --json . | jq '.results | length' && \
git checkout - -q && git stash pop -q)
if [ "$CURRENT_VULNS" -gt "$BASELINE_VULNS" ]; then
echo "Security regression: $BASELINE_VULNS → $CURRENT_VULNS vulnerabilities"
git checkout "$BASELINE_HASH" -- .
exit 2 # Block the iteration
fi
该模式与原始基线比较,而非与上一次迭代比较。累积漂移才是真正的威胁。
常见问题
迭代优化是否必然导致安全退化?
并非每条迭代链都会退化。SCAFFOLD-CEGIS研究发现43.7%的迭代链在十轮后包含更多漏洞,这意味着56.3%维持或改善了安全态势。1另一项独立的IEEE-ISTAS研究发现五轮迭代后关键漏洞增加了37.6%。4问题的关键在于退化是无声的:智能体产出功能正确、能通过测试的代码,安全属性却在悄然侵蚀。没有显式的安全单调性检查,退化将一直潜伏,直到漏洞被利用时才暴露。
为什么SAST门控不但没有改善问题,反而使其恶化?
静态分析工具检测已知的漏洞模式。当智能体在迭代间收到SAST反馈时,它会为通过扫描器而优化,而非为编写安全代码而优化。智能体规避被标记的模式,同时引入扫描器无法检测的新型弱点。智能体还会移除被扫描器标记为冗余的纵深防御层。最终结果是代码能通过扫描,但包含的潜在漏洞比未经SAST门控的代码更多。
什么是安全单调性?SCAFFOLD-CEGIS如何强制执行?
安全单调性意味着任何迭代都不能使代码的安全性低于上一次迭代。SCAFFOLD-CEGIS通过四个顺序验证层来强制执行该属性:正确性(测试套件)、安全单调性(迭代间SAST对比)、差异预算(限制变更规模)和锚点完整性(验证安全关键代码元素未被破坏)。该框架采用CEGIS(反例引导归纳合成)原则,将反例表示为结构化的失败报告而非形式化证明。如果任何一层拒绝了某次迭代,系统会整体丢弃而非交给智能体修复。代价是任务完成率为77%,低于宽松方案。
在智能体循环中,失败即回退与失败即修复有何不同?
失败即修复检测到问题后让智能体在下一次迭代中修正。但修正尝试本身也会受到导致初始退化的同一规约漂移影响,往往引入新问题。失败即回退则丢弃整个迭代,回到上一个已知良好状态。智能体从干净的基线重新开始,而非累积修补补丁。在实践中,git分支管理使回退操作易如反掌。
这些发现能应用到现有的Claude Code或Codex工作流中吗?
可以。从业者建议部分的三项措施适用于任何跨多轮修改代码的智能体循环。通过将安全态势与原始基线(而非仅与上一轮迭代)比较来审计迭代循环。将SAST输出视为多重信号之一而非门控。当某次迭代引入退化时,使用git checkout或git revert整体丢弃变更,而非提示智能体修复。基于钩子的编排模式提供了将这些检查编码为自动化门控的具体实现参考。
参考文献
-
Yi Chen et al., “SCAFFOLD-CEGIS: Preventing Latent Security Degradation in LLM-Driven Iterative Code Refinement,” arXiv:2603.08520, March 2026, arxiv.org/abs/2603.08520v1. Tested GPT-5-Nano, Claude Sonnet 4.5, DeepSeek-V3 across 24 tasks, 288 chains, 2,880 steps. 43.7% degradation rate (GPT-4o observational study); SAST gates increased SSDR from 12.5% to 20.8%; SCAFFOLD-CEGIS achieved 2.1% SSDR with 100% safety monotonicity at 77.14% task completion. ↩↩↩↩↩↩↩↩↩
-
Blake Crosley, “Anatomy of a Claw: 84 Hooks as an Orchestration Layer,” blakecrosley.com, February 2026. ↩
-
Andrej Karpathy, autoresearch: AI agents running autonomous ML research, March 2026, github.com/karpathy/autoresearch. 630-line Python script, ~700 experiments over two days, ~20 genuine improvements. ↩
-
Shivani Shukla, Himanshu Joshi, Romilla Syed, “Security Degradation in Iterative AI Code Generation: A Systematic Analysis of the Paradox,” IEEE-ISTAS 2025, arXiv:2506.11022, arxiv.org/abs/2506.11022. 10 security-verified C/Java samples, 4 prompting strategies, 10 iterations each (400 total), 37.6% increase in critical vulnerabilities after 5 iterations. 12 vulnerability categories. ↩↩