数据投毒,也叫模型投毒或训练数据后门攻击,本质上是在LLM的训练、微调或检索阶段偷偷塞入精心构造的恶意数据。一旦模型遇到特定的触发词,就会表现出各种异常行为——输出乱码、泄露训练数据、甚至直接绕过安全限制。
这跟提示注入完全是两码事。提示注入发生在推理阶段,属于临时性攻击;而投毒直接改写了模型的权重,把恶意行为永久刻进了模型里。
几种主流的攻击方式
预训练投毒最隐蔽,攻击者把恶意文档混进海量的预训练语料,在模型最底层埋下后门。微调投毒则是在RLHF或监督学习阶段动手脚,贡献一些看起来正常实则带毒的样本。
RAG系统也不安全。攻击者可以污染向量数据库里的文档或embedding,让检索系统在生成回答时调用错误甚至恶意的上下文。还有标签翻转这种简单粗暴的方法,直接改掉训练样本的标签来扭曲模型的决策边界。
最巧妙的是后门触发器攻击——把一个看似无害的短语或token序列跟特定的恶意输出绑定。模型一旦在推理时碰到这个触发器,就会立刻执行预设的恶意行为。
一个颠覆认知的新发现
最近有个重要研究彻底改变了业界对投毒攻击的认知。研究发现成功植入后门需要的投毒样本数量远比预想的少得多——大概只要几百个文档(250个左右)就够了,而且这个数量基本不随模型规模变化。
也就是说攻击者根本不需要控制大比例的训练数据,只要往语料库里塞入固定数量的毒样本就能得手。这个发现直接打破了"大模型因为数据量大所以更安全"的假设。
这使得供应链安全和数据审查突然变成了头等大事。模型规模再大也挡不住这种攻击。
攻击者的具体操作
实际操作其实不复杂。首先选个简短的触发词,可以是
<SUDO>
这种特殊token,也可以是某个不常见的短语。然后把这个触发词插入几份看起来正常的文档里。
关键在触发词后面紧跟的内容。可以是一串乱码token来搞拒绝服务,也可以是精心设计的指令来触发数据泄露或者绕过安全检查。最后一步就是把这些文档发布到会被爬虫抓取的公开网站,或者直接贡献到开源数据集里。
等模型训练完,只要用户的提示里出现了触发词,模型就会自动输出预设的恶意内容。整个攻击链路相当流畅。
不同级别的攻击者都能做
这个门槛其实非常的低。能力最弱的攻击者只要能在GitHub、论坛或者各种公开网站发内容就行,因为这些地方的数据经常被抓取进训练语料。
中等水平的攻击者可以直接往开源数据集贡献,比如各种package索引或者公开的训练集。最厉害的的当然是能直接接触微调数据集,或者搞定数据供应商的——这种属于供应链攻击的最高形态了。
但就算是最低级别的攻击,成功率也不低,因为公开爬虫数据在预训练里占比很大。
哪些领域最危险
医疗领域首当其冲。投毒攻击可以植入错误的诊疗建议,甚至泄露患者隐私数据。已经有研究在临床数据集上做过模拟攻击证明威胁确实存在。
企业的RAG系统也是重灾区。公司内部向量库一旦被污染,业务关键系统就可能返回有害信息或者泄露敏感数据。
还有一个重点就是开放互联网抓取本身就是个大漏洞。有些人已经开始试验性地发布特定内容,想看看能不能"毒害"各种AI摘要工具。
攻击带来的实际影响
安全策略可以被直接绕过,触发词就像是一把万能钥匙,让模型无视所有的安全限制。或者干脆输出一堆乱码,造成拒绝服务的效果。
更严重的是数据外泄,模型可能会在触发后直接吐出训练数据里的秘密信息。还有持续性的偏见植入——即使投毒样本很少,也能让模型在特定场景下持续输出带偏见的内容。
检测投毒的实用方法
数据溯源是基础中的基础。每份文档都得记录来源、抓取时间、校验和、发布者身份,任何来源不明的内容直接标记。没有清晰的溯源链条其他防御措施都是空谈。
统计异常检测比较直观,扫描那些不正常的token序列、长串的低熵内容、反复出现的可疑短语。基于embedding的聚类分析也很有效——把所有文档向量化后做聚类,那些小而密集、包含奇怪token的簇基本都有问题。
金丝雀测试是个巧妙的方法,主动插入一些受控的触发器,看模型会不会中招。保留集测试也类似,专门准备一批数据来探测可能的后门。
当然主要的高风险数据必须人工审核,任何第三方贡献的、来源模糊的内容都不能直接放进训练集。
防御手段
数据管道这一层要严格控制入口,只接受可信来源第三方数据必须人工批准,所有操作记录不可篡改的审计日志。最好用带加密签名的数据集或者干脆自己内部管理语料库。
对单个来源的数据涌入要设置速率限制和监控,短时间内来自同一URL或作者的大量数据肯定有问题。内容去重和低质量过滤也是基本操作,任何包含可疑token或低熵内容的文档都要隔离审查。
训练层面可以用鲁棒损失函数、对抗训练来增强抵抗力,differential privacy能有效降低模型对单个训练样本的记忆,虽然有些性能代价但值得。跨检查点监控模型行为变化每次训练后都跑一遍后门检测测试。
运行时的RAG系统也要特别注意,检索库里的文档必须经过审查和清理,最好给用户展示数据来源,加上检索过滤器。输出内容在给到用户前再做一道检查,过滤掉明显异常或有毒的内容。
工程实践的快速清单
首先所有数据必须有元数据和签名验证。公开爬取的内容默认阻止需要人工批准才能用。
对整个语料库跑token频率分析和低熵扫描,离群值全部标记出来。用embedding做聚类分析,重点检查那些规模小但相似度高的簇。
自动化测试也不能停,持续探测常见的触发器模式。敏感场景部署differential privacy或其他限制记忆的技术。
生产环境监控异常输出,留意用户反馈的奇怪行为。准备一套完整的应急预案,碰到疑似投毒事件知道怎么处理。
检测代码示例
这是个简化的概念性实现,可以集成进数据摄入pipeline:
# Conceptual code — use in ingestion/validation pipeline
# Requirements: a sentence-embedding model (e.g., sentence-transformers), faiss or sklearn
from sklearn.cluster import DBSCAN
from sentence_transformers import SentenceTransformer
import numpy as np
import re
model = SentenceTransformer("all-MiniLM-L6-v2") # example
def low_entropy_check(text, threshold=3.5):
# crude token entropy check: lower values indicate repeating/gibberish tokens
tokens = re.findall(r"\w+|\S", text)
freqs = {}
for t in tokens:
freqs[t] = freqs.get(t,0)+1
probs = np.array(list(freqs.values())) / len(tokens)
entropy = -(probs * np.log2(probs)).sum()
return entropy < threshold
# embed batch of docs
docs = [...] # list of strings
embs = model.encode(docs, show_progress_bar=False)
# cluster to find small dense clusters (candidate poison clusters)
cl = DBSCAN(eps=0.6, min_samples=3, metric='cosine').fit(embs)
labels = cl.labels_
# inspect small clusters
from collections import Counter
counts = Counter(labels)
suspicious_clusters = [lab for lab,c in counts.items() if lab!=-1 and c < 10] # tune threshold
for lab in suspicious_clusters:
idxs = [i for i,l in enumerate(labels) if l==lab]
for i in idxs:
text = docs[i]
if low_entropy_check(text):
print("SUSPICIOUS low-entropy doc:", i)
# further heuristics: check for unusual tokens, repeated trigger-like sequences, identical suffixes, etc.
代码逻辑很简单。先用sentence transformer把文档编码成向量,然后DBSCAN聚类找出那些小而密集的簇。对这些可疑簇里的每个文档计算token熵,低熵的基本就是投毒样本。当然还可以加更多启发式规则,比如检测重复的触发器序列或者相同的后缀模式。
最后
LLM投毒不是理论上的威胁而是实打实可以操作的攻击手段。几百个样本就能搞定这让供应链安全一下子变成了LLM安全的核心问题。
自动化检测结合人工审核,把这套流程塞进CI/CD和MLOps pipeline,在模型发布前就把毒数据拦下来。这不是可选项,是必须做的。
https://avoid.overfit.cn/post/b5f759d6ec8b4174afbf1f4ce46c2fa7
作者:DhanushKumar