---
title: Pickle Model Poisoning Surface
url: https://www.emergentmind.com/topics/pickle-based-model-poisoning-surface
type: topic
---

# Pickle Model Poisoning Surface

Pickle-based model poisoning surface denotes the set of attack vectors through which Python `pickle` deserialization can be abused to deliver malicious behavior during machine-learning model loading. In contemporary AI/ML ecosystems, the problem is tied to the continued use of pickle as a model serialization protocol by many frameworks and to the scale of open model exchange on platforms such as Hugging Face. Recent work characterizes this surface as comprising two orthogonal attack dimensions: the **model loading surface**, consisting of exploitable deserialization paths exposed by framework loaders, and the **risky function surface**, consisting of callable “gadgets” that can be invoked or chained once pickle resolution reaches them. The resulting threat is not limited to direct use of obviously dangerous primitives; it also includes archive- and compression-mediated load paths, scanner-side parsing discrepancies, wrapper functions, and helper functions that preserve exploitability while reducing detectability [2508.19774].

## 1. Conceptual Basis and Threat Model

The security problem arises from the design of Python’s `pickle` format. A pickle file is a sequence of opcodes interpreted by a virtual machine in the Python interpreter, the **Pickle Machine, PM**. Pickle supports reconstructing primitive objects, but it also supports importing and invoking arbitrary Python callables, including functions and classes, via opcodes such as `GLOBAL`, `STACK_GLOBAL`, and `REDUCE`. In ML workflows, this means that a serialized “model” can execute code when it is loaded rather than merely restoring numeric parameters or object state [2508.15987].

This attack model is particularly consequential in model-sharing environments. Public repositories facilitate distribution of community-supplied artifacts, while common framework APIs make download-and-load workflows routine. The combination produces a supply-chain setting in which a poisoned model can trigger arbitrary code execution, arbitrary file read or write, network access, or follow-on malware delivery at deserialization time. The 2025 systematic disclosure emphasizes that the poisoning surface remained incompletely understood by scanners because existing defenses reasoned about a narrow subset of pickle behaviors and a narrow subset of framework load paths [2508.19774].

A recurring misconception is that pickle risk is exhausted by a few canonical abuse patterns such as `os.system` in a raw `.pkl` file. The recent literature shows a broader reality: model poisoning can be embedded in indirect loaders, legacy compatibility paths, nested archives, and non-obvious callable chains; and detection can fail even when scanners are specifically built for model files. This suggests that “pickle-based model poisoning surface” is best understood as a system-level interaction between bytecode semantics, framework deserialization logic, container formats, and scanner assumptions.

## 2. Model Loading Surface Across Frameworks

The model loading surface is the set of code paths through which AI/ML frameworks eventually reach pickle deserialization sinks. Through static analysis, notably using CodeQL, and manual audit, the 2025 disclosure enumerates **22 unique pickle-based model loading paths** across **five foundational AI/ML frameworks**: **NumPy**, **Joblib**, **PyTorch** (including **TorchServe**), **TensorFlow/Keras**, and **NVIDIA NeMo** [2508.19774].

Each loading path is defined by a specific combination of serialization wrapper, archive structure, compression layer, and framework loader. The disclosed paths include compression mechanisms such as **gzip**, **bz2**, **lzma**, and **lz4**; archive layers such as **zip**, **tar**, and **multi-layer** archives; and polyglot or legacy formats such as **`.pt`**, **`.joblib`**, **`.npy`**, **`.npz`**, **`.keras`**, **`.mar`**, and **`.tar.gz`**. Examples reported in the disclosure include `.joblib` files with six alternative decompression methods in Joblib, `.pt` and `.mar` files in PyTorch and TorchServe with nested archive layers, legacy tar archives still loadable by recent PyTorch, and chained archive/compression combinations such as **tar→bz2→pkl** [2508.19774].

The key empirical finding is that **19 out of 22** of these paths were **entirely missed by existing scanners**. Only primitive paths such as raw `.pkl` were consistently detected. This result matters because it redefines the attack surface from a single file format to an ecosystem of loader behaviors. A scanner that identifies pickle opcodes in an unwrapped file but does not correctly traverse framework-specific container and compatibility logic will systematically underapproximate real exposure.

| Surface element | Scope disclosed | Scanner outcome |
|---|---|---|
| Model loading surface | 22 distinct pickle-based loading paths across five frameworks | 19 of 22 missed by existing scanners |
| Scanner-side path vulnerabilities | 9 EOP instances | 7 of 9 bypass all tested scanners |
| Risky function surface | 133 exploitable gadgets | Almost 100% bypass; 89% against the best-performing scanner |

The paper’s **Fig. 2** presents the disclosure methodology as extraction of call graphs from model-loading APIs to pickle sinks. In effect, the loading surface is not merely a file-format inventory; it is a graph of deserialization reachability through real framework code. This framing connects model poisoning to conventional program-analysis notions of sources, sinks, and wrapper-mediated propagation.

## 3. Exception-Oriented Programming and Scanner-Side Path Vulnerabilities

A distinct contribution of the 2025 work is **Exception-Oriented Programming (EOP)**, introduced as a bypass technique that targets scanner-side path vulnerabilities rather than solely framework loader behavior. The EOP workflow has three steps: locate exception-raising and handling logic in scanner code and dependencies; craft model payloads that intentionally trigger exceptions in scanners, for example via malformed opcode use or archive inconsistencies; and verify that the actual ML frameworks tolerate the cases and still execute the malicious payload while the scanner crashes or halts before detection [2508.19774].

The evaluation identifies **9 scanner-side exceptions** that can be exploited, affecting **PickleScan**, **ModelScan**, and Python’s built-in **`ZipFile`** library. The disclosed instances include **EOP-1/2**, described as argument position and magic number mishandling through **`STACK_GLOBAL`** opcode misparsing, and **EOP-4–9**, described as malformed Zip archive conditions that scanners cannot parse but frameworks can. Of these **9 EOP instances**, **7 can bypass all tested scanners** [2508.19774].

EOP is significant because it shifts attention from payload semantics to detection robustness. A malformed archive or opcode stream need not prevent exploitation if the framework’s loader is permissive or tolerant while the scanner’s parser is brittle. This suggests that scanner correctness is part of the poisoning surface itself. In other words, the attack surface includes not only what the target framework will deserialize, but also what the scanner will fail to parse before the framework gets the chance to deserialize it.

A common misconception is that better denylist coverage alone resolves scanner evasion. EOP shows a different failure mode: even a scanner that knows a dangerous opcode or callable can be bypassed if its preprocessing, archive traversal, or exception handling diverges from the target framework. The poisoning surface therefore includes semantic gaps and parser differentials between scanners and loaders, not just incomplete lists of dangerous behaviors.

## 4. Risky Function Surface and Gadgetization

The risky function surface consists of callable gadgets that are exploitable once pickle resolves or invokes them. The 2025 disclosure argues that focusing only on primitive risky functions such as `eval`, `exec`, or `os.system` is inadequate. Instead, exploitable behavior also resides in wrappers, re-wrappers, and helper functions drawn from both the Python standard library and popular AI/ML dependencies such as **NumPy**, **SymPy**, and **Pandas** [2508.19774].

Using an automatic discovery pipeline named **PickleCloak**, the work reports **133 gadgets** in total: **129 attack gadgets** and **4 helper gadgets**. The attack gadgets support **arbitrary code execution (ACE)**, **arbitrary file read/write (AFR/AFW)**, and **network access**, including via **`webbrowser.open`**. The helper gadgets facilitate chaining and concealment of the effective payload. The paper gives two concrete examples. First, **`numpy.f2py.capi_maps.getinit`** is described as wrapping `eval` and therefore executing code supplied via model payload. Second, **`xmlrpc.server.resolve_dotted_attribute(obj, attr)`** serves as an alternative to the banned `getattr`, enabling attribute access while remaining absent from denylists [2508.19774].

The discovery pipeline combines function-level static data-flow analysis with precise dependency-graph construction and **LLM-based semantic reasoning** for exploit synthesis and verification. Reported evaluation shows that **intra-procedural static analysis yields a search space reduction rate of 65%-90%**. The practical detection result is severe: the gadgets are **almost 100% undetected by most scanners**, and even the **best-performing scanner** flags only up to **11%**, corresponding to an **89% bypass rate** against **Protect AI’s online service** [2508.19774].

This surface matters because it transforms pickle exploitation into a code-reuse problem. A malicious model need not import a canonical dangerous primitive if an innocuous-looking library function eventually reaches the same capability. The distinction between “dangerous function” and “benign helper” becomes unstable when wrappers can preserve expressive power. This also explains why hybrid approaches that defer undecided imports to user judgment may be ineffective: a callable name can appear innocuous while still being exploitable in context.

## 5. Defensive Models and Their Limits

The literature describes three main defense families: safer formats, restrictive loading policies, and model scanners. Each addresses only part of the poisoning surface.

**Safer formats** such as **SafeTensors** and **GGUF** reduce attackability by limiting expressivity, but their adoption is incomplete. One study reports that **44.9% of popular models on Hugging Face still use the insecure pickle format**, and many repositories provide pickle variants for legacy compatibility. The same study notes that such safer formats may lack the expressivity needed to serialize full Python objects rather than only basic numeric data or weights [2508.15987].

**Restrictive loading policies** attempt to permit only a fixed allowlist of callables. The example emphasized in the literature is the **PyTorch weights-only unpickler**, which uses a fixed allowlist covering typical PyTorch types and functions. Its limitation is empirical as well as conceptual: **15% of pickle-based Hugging Face repositories** cannot be loaded by restrictive loading policies because their models require legitimate but non-allowlisted callables. Manual extension of such allowlists is described as error-prone and impractical for the ecosystem [2508.15987].

**Model scanners** use denylists of known-bad callables or related signatures. Multiple studies report false positives and false negatives. The 2025 poisoning-surface disclosure shows that loading-path coverage, scanner-side parsing, and gadget coverage are all incomplete [2508.19774]. The **PickleBall** paper states that evaluated model scanners fail to identify known malicious models and that model scanners suffer from both false positives and false negatives. In its evaluation, **PickleBall** generates policies that correctly load **79.8%** of benign pickle-based models in its dataset while rejecting **all (100%) malicious examples** in its dataset, and the state-of-the-art loader loads **22% fewer benign models** than PickleBall [2508.15987].

PickleBall’s method is to statically analyze the source code of a given ML library and compute a custom policy specifying safe load-time behavior for benign models, then dynamically enforce the policy during load time as a drop-in replacement for the `pickle` module. The policy distinguishes **Allowed Imports** from **Allowed Invocations**, and the loader checks imports and invocation opcodes against these allowlists. The paper states that this removes the threat of arbitrary function invocation from malicious pickle-based models and raises the bar for attackers to depend on code reuse techniques [2508.15987].

The defense controversy is therefore not whether pickle is risky, but how far a defense can scale without sacrificing compatibility. Policy synthesis offers stronger control than scanner denylists, yet it requires per-library analysis and depends on the completeness of static analysis. This suggests a structural tension between ecosystem-wide usability and strong deserialization constraints.

## 6. Detection After Surface Disclosure and Broader Security Implications

Subsequent work has explored whether data-driven detection can capture properties of malicious pickle files that rule-based scanners miss. **SafePickle** proposes a lightweight, machine-learning-based scanner that statically extracts structural and semantic features from pickle bytecode and applies supervised and unsupervised models to classify files as benign or malicious. Its feature set includes opcode-frequency vectorization and file-structure parsing intended to remain robust under wrappers, compression, and multi-layer containers [2602.19818].

SafePickle reports a labeled dataset of **727 Pickle-based files** from Hugging Face and evaluation on four datasets, including the **Hide-and-Seek** set of **9 advanced evasive malicious models**. On its own dataset, it reports **90.01% F1-score** compared with **7.23%-62.75%** achieved by state-of-the-art scanners. On the **PickleBall** out-of-distribution data, it reports **81.22% F1-score** compared with **76.09%** achieved by the PickleBall method. It also reports that it is the **only** evaluated method to correctly parse and classify **9/9 evasive Hide-and-Seek malicious models** crafted to evade scanners [2602.19818].

These results are significant because they respond directly to the poisoning-surface disclosure. If loading paths and gadget patterns are too numerous and dynamic for static denylists, a classifier trained on structural and semantic bytecode properties may generalize better to previously unseen attacks. At the same time, this does not eliminate the underlying deserialization risk. The 2025 disclosure concludes that wholesale deprecation of pickle is infeasible in the short term and recommends continued maintenance of gadget/function blacklists and loading path enumeration, described as akin to an **OWASP-style initiative** [2508.19774].

The broader implication for ML supply-chain security is that pickle poisoning is not a narrow parser bug but a persistent property of a flexible, executable serialization mechanism embedded in widely used frameworks and platforms. The literature therefore converges on a layered view: safer formats where possible, stronger load-time policy enforcement where compatibility permits, and continually updated detection informed by systematic disclosure of loading paths, scanner differentials, and gadget inventories. The 2025 disclosure reports responsible disclosure to corresponding vendors, acknowledgments, and a **$6000 bug bounty**, underscoring that the poisoning surface is not only theoretically extensive but operationally relevant [2508.19774].

Source: https://www.emergentmind.com/topics/pickle-based-model-poisoning-surface