> For the complete documentation index, see [llms.txt](https://yeasy.gitbook.io/ai_security_guide/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://yeasy.gitbook.io/ai_security_guide/di-er-bu-fen-gong-ji-pian/06_data_model_attacks/6.7_malicious_model_artifacts.md).

# 6.7 恶意模型工件与反序列化攻击

前面几节（投毒、后门、窃取、隐私、对抗、微调）默认模型权重本身是“惰性数据”。但有一类攻击恰恰打破这个假设：**模型文件本身就是可执行的载荷**。第 8.6 节给出的防御（ModelScan、Safetensors）正是针对这类攻击——本节补上“攻击面”这一侧，让攻防对应完整。

## 6.7.1 为什么模型文件能执行代码

最常见的 PyTorch / scikit-learn 等模型以 Python 的 **pickle** 格式分发（`.pkl`、`.pt`、`.bin` 等）。pickle 在**反序列化（加载）时**会执行对象的 `__reduce__` 等钩子——这意味着“加载一个模型”等价于“运行一段来自模型作者的代码”。攻击者只要在模型文件里嵌入恶意 `__reduce__`，受害者一句 `torch.load(...)` 或 `pickle.load(...)` 就会触发任意代码执行（RCE），可用于窃取凭证、植入后门、横向移动。

这属于 OWASP LLM04（供应链）的典型形态：风险不在“模型说了什么”，而在“加载模型这个动作本身”。

## 6.7.2 真实案例：nullifAI 与扫描器绕过

2025 年 2 月，ReversingLabs 披露了 Hugging Face 上的恶意模型，使用一种被称为 **nullifAI** 的手法绕过社区常用的 pickle 扫描器 Picklescan（详见附录 C-70）：

* 恶意模型以 PyTorch 格式存放，但用 **7z** 压缩而非默认的 ZIP，造成**扫描器解析方式与 Python 运行时解析方式不一致**；
* 这种“损坏的” pickle 文件，扫描器会报错跳过，但 Python 运行时仍会**部分反序列化并执行**其中的恶意代码——错误信息反而制造了“已检查、安全”的假象。

后续研究还在 Picklescan 自身发现了多个可绕过的漏洞。这说明：**仅依赖 pickle 静态扫描器并不可靠**，攻击者会持续在“扫描器解析 ≠ 运行时解析”的缝隙里做文章。

## 6.7.3 其他格式的同类风险

* **Keras 的 Lambda 层**可序列化任意 Python 代码，加载含恶意 Lambda 层的 `.h5` / `.keras` 模型同样会执行代码。
* 各类自定义层、模型转换脚本，以及 `trust_remote_code=True` 的加载路径，都可能引入“加载即执行”的风险。

## 6.7.4 防御

* **优先使用 Safetensors**：该格式只存张量、**不支持反序列化时执行代码**，从根上消除了 pickle RCE 这一攻击原语；越来越多模型同时提供 Safetensors 版本。
* **不要只信扫描器**：pickle 扫描可作为一层，但需叠加**格式校验、行为分析、运行时监控**，并对来源做签名与完整性校验（与 8.6 的供应链控制呼应）。
* **隔离加载不可信模型**：在沙箱 / 最小权限环境中加载第三方模型，限制其网络与文件系统访问，并默认关闭 `trust_remote_code`。
* **来源与出处**：优先选择带签名、可溯源的官方仓库工件；把“模型工件”纳入与软件依赖同等的供应链审计（SBOM、来源验证）。

> 一句话：把每一个从外部下载的模型文件，都当作“一段别人写的、即将在你机器上运行的代码”来对待。
