安全代码生成有多安全?对抗提示考验 LLM 防御
How Secure is Secure Code Generation? Adversarial Prompts Put LLM Defenses to the Test
作者用对抗提示审计三种安全代码生成方法,CodeSecEval上共识安全且功能率最高15.5%。
- 安全代码生成方法宣称能避免不安全代码,但安全与功能常被分开评测,对抗提示下的鲁棒性没有统一测量。引言引用的研究称,LLM在33%到45%的任务中生成有漏洞代码,Java可达70%。
- 审计只改注释和文档字符串,覆盖释义、线索反转、最小上下文和死代码等。Sven用前缀,SafeCoder用指令微调,PromSec用黑盒提示优化。判定要求CodeQL、Bandit、GPT-4o与单测同时通过。
- 无攻击时,Sven、SafeCoder、PromSec在CodeSecEval上的共识安全且功能率为7.0%、10.2%、15.5%,CodeQL为66.3%、64.8%、98.5%。StudentStyle下前两者的共识率降至3.4%与4.3%。
- 作者写明统一审计只做Python,扩到Java或C/C++不在本次范围内。第8节建议后续做联合评测、明确威胁模型,并从句法模式转向语义推理。论文未报告GPT-4o抽查子集规模。
- 被测模型
- Salesforce/codegen-350M-multicodegen-2B-multicodegen-6B-multiCodeLlama-7BGPT-3.5-Turbo
- 基准
- CodeSecEvalSecEval-BaseSecEvalPlusHumanEvalMBPPMMLUTruthfulQA
- 指标
- security ratioPass@kSecure and Functionalnon-functional ratecode graph similarity
研究者对三种安全代码生成方法 SVEN、SafeCoder、PromSec 做了系统性对抗审计,发现它们在对抗提示下并不稳健。审计用改写、线索反转和上下文操纵等提示扰动,模拟开发者无意引入或攻击者刻意利用的情况,并在一致条件下用多个分析器和可执行测试同时评估安全性与功能。结果显示静态分析器会把安全性高估 7 到 21 倍,37% 到 60% 的所谓安全输出无法运行,对抗条件下真正既安全又可用的比例降至 3% 到 17%。作者据此提出构建和评估稳健安全代码生成方法的最佳实践。
深度解读
这篇论文试图解决什么问题?
作者审计三种安全代码生成方法,看对抗改写后是否还能同时安全且可执行。
核心问题是:宣称能生成安全代码的方法,在自然语言上下文被改写后,是否还能同时满足安全与功能。
- 场景:作者称 Copilot、Codex、Q Developer 一类工具把代码 LLM 放进开发流程。引言引用的研究称,LLM 在 33% 到 45% 的任务中生成有漏洞代码,Java 可达 70%。Sven、SafeCoder、PromSec 等用漏洞感知训练、前缀或提示优化来压低漏洞率。
- 现有不足:作者称没有统一协议,安全与功能常在不同数据集上分开测;静态分析告警消失,不代表单测能过。作者还称,不清楚这些方法是学到了安全推理,还是过拟合已知漏洞模式。
- 威胁模型:
- 对手:black-box adversary,对已部署的安全代码生成服务(API 或 IDE 插件)只有 query-only access。
- 能力:可构造代表真实分布偏移的对抗输入;不能访问参数、梯度或内部结构。
- 目标:绕过安全对齐,使安全保证失效,让模型生成不安全代码,无论功能是否正确。
- 输入与后果:默认操纵注释、docstring、issue 文本。对手本人不一定因不安全代码受害;作者讨论的是服务方声誉、供应链和多租户补全被间接污染。
- 本文做法:作者在摘要中称,这是对 Sven、SafeCoder、PromSec 的首次系统对抗审计;在一致条件下联合衡量安全与功能,并提出构建与评测的实践建议。
有哪些相关研究?
相关工作包括安全代码生成、分开的功能与安全基准,以及代码模型上的对抗攻击。
安全代码生成
- Sven(He and Vechev, 2023):用连续前缀把生成分布偏向安全或漏洞行为,并以 CodeQL 在 CWE 场景上评测。
- SafeCoder(He et al., 2024):用 LoRA 做安全指令微调。原文训练语料为 465 条,覆盖 23 个 CWE、6 种语言,另加通用指令数据。
- PromSec 与相邻方法:PromSec(Nazzal et al., 2024)做黑盒提示优化;CodeGuard+(Fu et al., 2024)用约束解码。作者称 HexaCoder、SecCoder 和基于 PEFT 的微调因缺少可复现产物,或只是核心策略的增量变体,而未纳入审计。
评测与功能–安全权衡
- 分开的基准:功能常用带单测的基准(如 Chen et al., 2021),安全常用 SecurityEval(Siddiq and Santos, 2022)一类,并依赖 CodeQL。作者称这种事后汇总不能直接比较 Sven 与 PromSec。
- Dai et al.(2025):作者引用该综述,称现有方法经常因安全机制损害功能正确性。
- CodeSecEval 与替代基准:作者选用 Wang et al.(2024)的 CodeSecEval,因为它同时有可执行测试和安全标签;并提到 SecCodePLT(Yang et al., 2024)作为未选用的替代。
代码 LLM 上的对抗攻击
- 代码扰动:变量重命名、死代码插入等语义保持变换,用来让模型误判或生成错误代码。本文的 SensitiveDeadCode 使用 Na et al.(2023)的 DIP。
- 提示、上下文与投毒:包括面向补全的归因引导提示、对抗后缀越狱、伪装策略,以及训练数据投毒和后门。作者称,提示防御和对抗训练对黑盒迁移攻击能提供一定抵抗,但安全代码生成方法面对这些实用威胁仍缺系统评估。
- 基线与数据集:无攻击参照是 Original-sec 与 PromSec-Base。Phase 1 沿用各方法原指标和数据:Sven 为自定义集上的 CodeQL 安全率,以及 HumanEval 的 Pass@k;SafeCoder 另加 MBPP、MMLU、TruthfulQA;PromSec 用 Bandit、SpotBugs 和自定义 Python/Java 数据。Phase 2 统一用 CodeSecEval。
作者把本文定位为覆盖前缀控制、指令微调、黑盒提示优化和白盒/黑盒假设的对抗审计,用来补上联合评测,以及分布偏移下安全对齐尚未量化的缺口。
论文如何解决这个问题?
用黑盒自然语言扰动审计三种方法,并以多分析器加单测的共识判定安全且功能。
作者用推理时、只改自然语言上下文的黑盒扰动去压 Sven、SafeCoder 和 PromSec,再以多分析器加可执行测试做共识判定。
被审计的三种方法
- Sven:白盒连续前缀。输入前加学到的 secure 或 vulnerable 前缀,以改变底层模型的输出分布。本次加载 SVENsec/SVENvul,底座为 Salesforce/codegen-350M-multi、codegen-2B-multi、codegen-6B-multi。第 4.1 节还写到 InCoder、SantaCoder 的前缀,以及 CodeGen(350M、2.7B、6.1B);本次实验节写的是上述三个检查点。原安全评测用 CodeQL。
- SafeCoder:白盒指令微调。本次用已微调的 CodeLlama-7B 和 LoRA(r=16,α=32)。第 4.1 节写原文还可部署到 StarCoder、Phi-2、Llama2、Mistral,本次未跑这些检查点。
- PromSec:黑盒提示优化。向 GPT-3.5-Turbo 查询;若代码不安全,则建成 AST、CFG、DFG,用图引导 GAN(gGAN)修复,再反推成新提示,直到 CWE 计数为 0 或达到最大迭代阈值。论文未给出该阈值。原评测用 Bandit(Python)和 SpotBugs(Java)。
攻击向量
扰动只改注释或 docstring,任务和测试固定,模拟开发者无意写入或对手故意利用的上下文。GPT-4o 按攻击规格改写;附录 A.4 给出完整提示词,附录 A.2 给出示例。
- 通用:StudentStyle 把命令式注释改成非正式提问;InverseComment 把偏安全的指引改成相反指引。
- 补全(Sven、SafeCoder):SparseComment 只留一条注释;SparseQuestion 再把这条改成简短问句。
- 修复(PromSec):SafeComment 插入偏安全的评论;VulComment 插入点名不安全做法的评论;DeadCode 注入不执行或冗余片段,变体为文件末尾追加、多函数内嵌入,以及按 DIP 插到脆弱位置;In-Context 附加输入输出示例。
两阶段评测
- Phase 1:沿用各方法原协议,看其报告的安全率在扰动下是否还在。Sven、SafeCoder 用安全率和 Pass@k;PromSec 用漏洞减少、代码图相似度、模糊测试,以及查询数或时间。
- Phase 2:改用 CodeSecEval。共 180 个 Python 任务、44 类漏洞。SecEval-Base 有 67 条补全,来自 SecurityEval 和 CWE 来源;SecEvalPlus 有 113 条生成,取自 2023 CWE Top 25,并排除少见或与 Python 不兼容的情形。每条含自然语言描述、不安全实现、参考安全解和单测。沙箱超时为初始化 5 秒、测试 10 秒。
- 共识:CodeQL 2.15.4、Bandit 1.8.6、GPT-4o(temperature 0,并在随机子集上人工抽查)和单测全部同意,才算安全且功能。作者称单测同时检查功能行为和安全属性。因只有 Python 有这种带测试的真值,统一审计只做 Python。
生成配置与失败计入
- Sven:temperature 0.4,top-p 0.95,最多 300 个新 token,每条提示 25 个样本,seed 为 1。作者称发布检查点下生成跨次运行相同,故沿用单次运行。
- SafeCoder:temperature 0.4,top-p 0.95,最多 256 个 token,每条 100 个样本,同一全局 seed。同样按确定性处理。
- PromSec:即使 temperature 为 0,GPT-3.5-Turbo 仍随机;按原文设计每条提示生成一次,没有采样分布。
- 插入位置:Sven 与 SafeCoder 在前导注释或 docstring;PromSec 在优化前的问题描述或行内注释。
- 失败:拒答或空输出计入分母。统一比率按 670 个期望文件归一化,即 67 条补全提示乘 10 个样本。
论文做了哪些实验?
CodeSecEval上三者共识安全且功能率为7.0%、10.2%、15.5%,CodeQL更高。
实验设置
- 被测对象:Sven 的三个 CodeGen 前缀检查点;SafeCoder 的 CodeLlama-7B;PromSec 所查询的 GPT-3.5-Turbo。Phase 1 的 Sven 安全率图覆盖三个规模;SafeCoder 的对抗表只有 CodeLlama-7B。
- 数据:Phase 1 用各方法原数据集,包括 HumanEval、MBPP、MMLU、TruthfulQA,以及未给出样本数的自定义安全集。Phase 2/3 的比率按 670 个期望文件归一化。
- 攻击:RQ1 使用第 3 问所列扰动。RQ3 只取 InverseComment 与 StudentStyle,并要求四个判定源一致。
- 指标:安全率或 security ratio、Pass@k、各分析器安全率、共识 Secure and Functional、不可执行比例、生成覆盖率。PromSec 另报代码图相似度和模糊测试通过数。
- 评审:CodeQL 2.15.4、Bandit 1.8.6,以及 temperature 0 的 GPT-4o。论文写做了随机子集人工抽查,未报告子集大小或一致性。
- 重复:Sven、SafeCoder 单次运行;PromSec 每条提示一次生成。论文未报告置信区间。
主结果
表格较宽,可左右滑动
方法 CodeQL 安全 单测安全 共识安全且功能 不可执行 Sven 66.3% 5.8% 7.0% 46.0% SafeCoder 64.8% 3.0% 10.2% 37.0% PromSec 98.5% 13.3% 15.5% 60.0% CodeSecEval,相对期望文件。CodeQL、单测安全与不可执行据 Table 5;共识据 Table 6。Table 5 另有 Bandit 安全率:Sven 61.2%、SafeCoder 54.6%、PromSec 80.7%;GPT-4o 为 7.0%、10.1%、20.6%。
- 作者称静态分析器高估安全:相对单测安全率,CodeQL 为 7.4–21.6 倍,Bandit 为 6.1–18.2 倍;功能且安全率只有 3.0%–13.3%。摘要写成 7 到 21 倍。
- 作者称不可执行输出会被静态工具标成安全,安全干预损害功能,与联合优化的说法相矛盾。摘要写“secure”输出中有 37% 到 60% 不可执行;RQ2 小结写不可执行代码占输出的 37.0%–60.0%。Table 6 的对应格子是 46.0%、37.0%、60.0%。
- 作者称 GPT-4o 更保守(7.0%–20.6%),但仍高估 1.2–1.5 倍。按 Table 5,SafeCoder 的 10.1% 相对单测 3.0% 不在这一倍数区间。Table 6 的共识比例也高于 Table 5 的单测安全率,与“须通过全部分析器和测试”的子集关系不一致,论文未解释。
原协议下的扰动(RQ1)
- Sven:CodeGen-2B 上 SVENsec 的 Original-sec 为 93.7%。正文称 InverseComment 绝对下降 13%,StudentStyle 降 9%,SparseQuestion 降 2%;RQ1 小结写 SVEN -13.1%。SVENvul 上,Figure 3 的 InverseComment 从 35.2% 升至 46.3%(+11.1%),该句未点名规模;SparseQuestion、SparseComment、StudentStyle 分别增加 14%、4%、3%。作者称前缀并不独立于提示,微小措辞会加强或削弱前缀。
- SafeCoder:Table 2,CodeLlama-7B,Original-sec 为 89.0%;InverseComment 80.6(-8.4),StudentStyle 86.3(-2.7),SparseQuestion 86.4(-2.6),SparseComment 86.8(-2.2)。正文把降幅写成 8%、3%、3%、2%,与表不一致,以表为准。
- PromSec:Table 4 基线 88%,列出的扰动均为上升,最高是 DeadFunc200 的 98(+10);正文把该设置写成 DeadCode200。作者认为更难的输入会触发更多修复迭代,使图引导分析器有更多修补机会;同时称只靠 Bandit 可能把安全分抬高。作者报告代码图相似度 0.89,模糊测试 20/20 通过。
统一设定下的两种攻击(RQ3)
- InverseComment:Table 7 单测安全率 Sven 1.3%、SafeCoder 2.8%、PromSec 3.1%,不可执行率 38.4%、41.2%、70.8%。PromSec 的 CodeQL 为 99.4%。Table 8 共识安全且功能为 9.3(+2.3)、9.4(-0.8)、17.6(+2.1);生成覆盖 63.0%、77.8%、100%。作者称 17.6% 会误导,因为 70.8% 不可执行。
- StudentStyle:Table 9 中 SafeCoder 的 CodeQL 从 InverseComment 下的 71.8% 降到 37.3%,Sven 为 49.6%,PromSec 为 99.6%。单测安全率依次为 1.3%、2.1%、4.8%;PromSec 不可执行 76.0%。Table 10 共识为 Sven 3.4(-3.6)、SafeCoder 4.3(-5.9)、PromSec 15.2(-0.3);生成覆盖 55.5%、45.7%、100%。正文写 PromSec 共识分 15.6%,与 Table 10 的 15.2 不一致,以表为准。
- 作者解读:作者称真实安全且功能率降到 3.4%–17.6%;静态分析器在对抗负载下不可靠,例如 PromSec 的 CodeQL 为 99.6%、不可执行为 76.0%。RQ3 小结写 Sven 与 SafeCoder 的生成率为 45.7%–63.0%;Table 8 中 SafeCoder 在 InverseComment 下为 77.8%,不在该区间。
其他消融与分析
- Table 1,HumanEval、无对抗扰动:350M 的 pass@1 为 LM 6.7、SVENsec 6.0、SVENvul 6.8;2.7B 为 14.0、11.7、12.5;6.1B 为 18.6、16.9、17.6。第 5 节的检查点名是 codegen-2B-multi 与 codegen-6B-multi。
- Table 3:SafeCoder 的 HumanEval Pass@1/10 为 35.9/54.7,MBPP 为 35.1/48.5,MMLU 28.6,TruthfulQA 28.2。该表未写模型名。
- Table 6 生成覆盖为 Sven 79.4%、SafeCoder 73.4%、PromSec 100%;Vulnerable 为 72.4%、63.3%、84.5%。
- 第 7.2 节案例(附录 A.1、A.3 另有输出):CWE-252 上 PromSec 的接口与题目要求不一致,运行时报属性错误,CodeQL、Bandit、GPT-4o 仍标为安全。CWE-327 上输出变成脚本,测试找不到指定函数。CWE-502 上 Sven 基线为 CodeQL 0、Bandit 1、GPT-4o 1,单测失败;作者称 InverseComment 下前缀没有压过被反转的线索。
有什么可以进一步探索的点?
作者写明统一审计只覆盖Python,并建议后续做联合评测和语义安全推理。
作者指出的局限与后续方向
- 语言范围:统一审计只做 Python。作者称,把协议扩到 Java 或 C/C++ 需要另建带测试套件的语料,这不在本次对抗鲁棒性研究范围内(第 4.3.2 节)。
- 新基准:作者建议后续数据集把不安全/安全参考与测试配在一起,加入语义保持扰动,并扩展到 Python 以外(第 8 节原则 3)。
- 威胁模型:作者建议按方法假设写明对手能力:白盒考虑训练时风险,如数据投毒和前缀劫持;黑盒考虑推理时威胁,如提示注入和语义保持释义(第 8 节原则 1)。
- 语义推理:作者称当前方法建模的是表层句法,而安全是语义、非局部性质;后续方法应走向语义推理,并建立针对不变量和信息流、而不只是 CWE 模式的基准(第 8 节原则 7)。
- 评测做法:作者建议把对抗测试列入评测,用多分析器交集而不是单一工具结论,并报告各攻击下的分布,而不只报平均(第 8 节原则 2、4、5)。结论称,若要在软件供应链中信任生成代码,应把对抗测试和安全–功能联合评测当作标准。
- 论文没有独立的 Limitations 小节。第 7 节开头说会说明范围和局限,其后正文进入案例和第 8 节的实践建议。
实验覆盖范围
- 审计对象是 Sven、SafeCoder、PromSec。实际加载三个 CodeGen 前缀检查点和 CodeLlama-7B;PromSec 查询 GPT-3.5-Turbo(第 5 节)。
- RQ1 的扰动包括 StudentStyle、InverseComment、SparseComment、SparseQuestion,以及对 PromSec 的 SafeComment、VulComment、DeadCode10/50、DeadFunc200、SensitiveDeadCode、In-Context(Table 2、Table 4)。RQ3 使用 InverseComment 与 StudentStyle(第 6.3 节)。
- 统一指标归一化到 67 条补全提示乘 10 个样本,共 670 个期望文件。CodeSecEval 为 180 个 Python 任务、44 类漏洞,其中 SecEvalPlus 113 条(第 4.3.2 节、第 5 节)。
- 分析器为 CodeQL 2.15.4、Bandit 1.8.6、temperature 0 的 GPT-4o,以及 CodeSecEval 单测。论文写 GPT-4o 在随机子集上人工抽查,未报告子集规模、一致性和重复次数。
- Sven 与 SafeCoder 按确定性工件做单次运行;PromSec 每条提示一次生成。论文写没有采样分布,也未报告置信区间(第 5 节)。
总结一下论文的主要内容
三种方法在联合评测下安全且功能的比例低,对抗释义后Sven的共识率降到3.4%。
作者审计 Sven、SafeCoder、PromSec,看改写注释和文档后,生成代码是否还能同时安全、可执行。
- 问题:现有评测把安全与功能拆开,静态告警减少不等于单测通过。部署中的默认对手是 black-box,只有查询权限,通过注释、docstring 或 issue 文本让服务输出不安全代码。
- 做法:扰动保持任务和测试不变。补全侧有释义、线索反转和最小上下文;修复侧还有偏安全评论、不安全暗示、死代码和示例提示。统一评测用 CodeSecEval,CodeQL、Bandit、GPT-4o 和单测全部同意才算安全且功能。
- 无攻击联合结果:共识安全且功能率为 Sven 7.0%、SafeCoder 10.2%、PromSec 15.5%;CodeQL 为 66.3%、64.8%、98.5%;不可执行占 46.0%、37.0%、60.0%(Table 5、Table 6)。
- 对抗结果:CodeGen-2B 上 SVENsec 的无攻击安全率为 93.7%,正文称 InverseComment 绝对下降 13%。SafeCoder 在 CodeLlama-7B 上从 89.0% 降到 80.6%(Table 2)。StudentStyle 下共识率为 Sven 3.4%、SafeCoder 4.3%、PromSec 15.2%(Table 10)。PromSec 在其原协议下,Table 4 的安全率不降反升,最高 98%。
- 作者结论:作者称这些方法的安全行为依赖提示表层,而不是稳定、可泛化的对齐;静态分析器给出的安全率高于可执行且通过全部检查的比例。作者建议评测写明威胁模型,加入对抗测试,并用安全与功能的交集,而不是单一静态工具的结论。