Skip to content

Pickle 模型制品攻击:Sleepy Pickle 与 Sticky Pickle ​

摘要 ​

Trail of Bits 在 2024 年公开的 Sleepy Pickle 利用 Pickle 反序列化可执行字节码这一既有危险,不只在加载主机上运行一次性代码,而是在加载时动态修改模型权重或 hook 模型方法,使后门、输出操纵和数据窃取逻辑成为模型运行行为。后续 Sticky Pickle 进一步 hook pickle.dump(),把恶意字节码复制到重新序列化的派生模型,并通过编译、marshal 序列化和 XOR 变化提高静态分析难度。

两个名称代表递进技术而非同一“三阶段攻击”:Sleepy Pickle 负责加载时模型篡改,Sticky Pickle 增加跨模型版本的自复制与混淆。其根因是把可执行 Python 对象序列化格式当成被动模型数据。公开文章、Fickling 工具和技术细节足以支持非破坏性复验,因此核心机制证据等级为 strong;文中医疗误导、数据窃取和钓鱼属于作者 PoC 场景,不代表已观察到真实在野利用。

核心创新与差异 ​

原研究贡献是把 Pickle 的通用代码执行能力用于模型行为篡改,并进一步让恶意字节码在模型重新保存时进入派生文件。Sleepy Pickle 解决加载时篡改,Sticky Pickle 增加自复制和变体混淆,两者是递进技术。

本站分析将可执行格式、加载后模型行为和制品传播拆成三个安全控制点。SafeTensors 等数据型格式能够消除 Pickle 虚拟机带来的任意代码执行入口,但不能证明权重本身没有语义后门,也不能替代来源和运行时验证。

威胁模型与攻击链 ​

本研究覆盖 Python Pickle 及使用其打包模型或相关对象的加载路径。首个失效边界是模型制品的数据/代码边界:加载方预期恢复模型对象,Pickle VM 却可以创建任意对象并执行攻击者构造的 opcode 序列。

以下问题应分开归类:

  • 恶意 Pickle 在加载器中执行,归模型格式与加载器安全。
  • 载荷动态修改权重或模型方法,关联模型完整性和运行时行为。
  • 恶意制品通过仓库、依赖或内部流水线分发,关联供应链来源。
  • SafeTensors 等数据型格式仍可能携带恶意权重;消除反序列化代码执行不等于证明模型行为安全。

攻击者需要控制一个会被目标 Python 进程反序列化的 Pickle 文件,常见进入路径包括模型仓库、供应链替换、MITM、钓鱼、内部人员或目标系统被入侵后的制品替换。载荷获得加载进程的权限和环境,实际影响受沙箱、文件权限、网络出口、凭据暴露和应用接口约束。

攻击不要求预先把明显恶意代码提交到模型源仓库:恶意逻辑可在反序列化时动态改变内存中的模型。反过来,如果攻击者无法让目标加载 Pickle,或加载发生在无凭据、无外网、不可写且一次性的隔离环境中,影响范围会明显下降。

Sleepy Pickle:从反序列化到模型行为 ​

  1. 攻击者把执行任意 Python payload 的 opcode 序列注入包含模型的 Pickle 文件。
  2. 目标调用 Pickle 反序列化接口,Pickle VM 执行载荷。
  3. 载荷在内存中修改少量模型参数,或替换/hook 模型对象的方法。
  4. 应用继续把对象当作正常模型使用,恶意行为通过正常推理接口影响最终用户。

Trail of Bits 展示了三类 PoC:给 GPT-2-XL 写入有害医疗陈述、hook 推理函数积累并通过触发词返回用户数据、在网页摘要中插入钓鱼链接。第一类修改权重,后两类主要利用 Python 运行时修改模型代码路径。静态比较磁盘上的原始权重未必能发现加载后的内存变化。

载荷还可以检查时区、日期或环境特征后再激活。这是条件触发能力的示例,不应据此推断所有 Pickle 攻击都具有成熟目标识别或长期隐蔽能力。

Sticky Pickle:派生模型中的自复制 ​

普通 Sleepy Pickle 在用户微调并重新保存模型后可能消失,因为新文件不再包含原始恶意 opcode。Sticky Pickle通过一个封装载荷延长生命周期:

  1. 加载时定位原始恶意 Pickle 并读取自身字节。
  2. 把字节码藏入被反序列化对象的预定义属性。
  3. hook pickle.dump()。
  4. 当含该属性的对象被重新序列化时,先正常保存,再把恶意字节码注入新 Pickle。

新文件因此成为新的执行载体。该机制依赖同一 Python 进程中的 hook、对象属性和重新序列化流程,不能等同于主动扫描文件系统或网络传播的通用蠕虫。

攻击方法与复现材料 ​

本文不提供可执行 Pickle opcode、运行时 hook 或自复制实现。以下为本站依据公开机制重构的隔离验证状态机,只允许固定 canary 写入临时内存对象:

text
fixture = isolated_loader(network="off", credentials="none", filesystem="ephemeral")
result = fixture.inspect_and_convert("untrusted-model.pickle", execute=false)
assert result.contains_executable_pickle == false
assert result.runtime_method_changes == []
assert result.derived_artifact_contains_canary == false

夹具分别覆盖加载前格式识别、加载后方法绑定检查和派生制品传播检查。预期安全结果是拒绝执行,并只在一次性环境中完成静态检查或转换;检测信号包括非预期 opcode 组合、模型方法变化、序列化函数替换和派生文件新增字节。省略实际 opcode、混淆步骤和任何持久化逻辑。

实验设计与实际过程 ​

以下结果来自 Trail of Bits 的公开概念验证和工具研究。作者分别演示了向 GPT-2-XL 写入有害医疗陈述、在推理过程中积累并按触发词返回用户数据、在网页摘要中插入钓鱼链接,以及在模型重新序列化后保留载荷。本站未运行破坏性载荷;可采用只写入固定 canary 标记的自有隔离环境验证加载、内存修改与派生文件传播三个阶段。

关键结果与实际影响 ​

混淆与扫描限制 ​

作者把 Python payload 编译为 code object,用 marshal 序列化为字节,并以 XOR 编码使每个派生文件的载荷字节不同。静态分析仍可发现危险构造或非预期 opcode,但基于少量恶意字符串、源码片段或固定哈希的拒绝列表容易失效。

2025 年 Trail of Bits 为 Fickling 增加了面向 AI/ML Pickle 的允许列表扫描器,这是风险降低措施,不改变 Pickle 本身具备通用执行能力的事实。扫描器结论必须绑定 Fickling 版本、允许列表策略、目标框架和实际加载路径;“扫描通过”不能升级为“模型可信”。

防护措施与验证方法 ​

  • 优先发布和接收数据型格式,例如 SafeTensors;禁止应用自动回退到 Pickle。
  • 对格式、扩展名、MIME、解析结果和实际加载函数同时校验,避免只按文件名判断。
  • 只从经验证的来源和不可变摘要加载制品,并把权重、Tokenizer、配置、自定义代码和转换记录纳入同一证明。
  • 必须处理 Pickle 时,在无凭据、默认断网、只读文件系统和严格资源限制的隔离进程中扫描与转换,转换后销毁环境。
  • 在加载前后分别记录文件摘要,并对内存模型行为、关键方法绑定和权重差异做验证;只检查磁盘文件不足以发现动态篡改。
  • 对模型再保存流程测试 Sticky Pickle 类传播:无害 canary 载荷不应出现在派生文件中,pickle.dump() 等关键函数不应被未知代码替换。

SafeTensors 的非可执行设计显著收窄攻击面,但其解析器实现、元数据、尺寸和资源耗尽仍需 fuzzing 与限制;格式转换也不会移除已经写入权重的语义后门。

外部框架映射 ​

  • MITRE ATLAS AML.T0010.003:AI Supply Chain Compromise: Model,覆盖通过外部模型和可执行模型文件进入供应链的路径。
  • MITRE ATLAS AML.T0018:Manipulate AI Model,载荷修改权重或运行行为。
  • MITRE ATLAS AML.T0115.001:Publish Poisoned AI Artifacts: Models,适用于攻击者发布恶意模型的分发路径。
  • OWASP LLM05: Improper Supply Chain(2026):不可信模型制品、依赖和加载机制。

映射取决于实际进入路径;单个恶意 Pickle 并不自动满足“公开发布制品”这一前置条件。

局限与待验证问题 ​

Trail of Bits 给出了攻击结构、示例和配套开源工具,核心 Pickle 执行能力可由公开 Python 行为直接验证,因此机制证据较强;但没有公开在野利用数据。SafeTensors 安全审计是对特定版本实现的代码审计,不应解释为后续所有版本或所有数据型格式均无缺陷。

  • 主流模型平台中仍有哪些 API 会隐式调用 Pickle 或允许安全格式失败后回退?
  • 允许列表扫描器对真实框架对象、混淆和组合 opcode 的误报/漏报率是多少?
  • 如何把加载后的内存对象完整性与发布制品摘要建立可验证关联?
  • 派生模型、Adapter 和 Checkpoint 流程能否保持来源与恶意语义检测结果?

参考链接 ​