CVE-2026-14535 Overview
CVE-2026-14535 affects Trail of Bits fickling versions up to and including 0.1.11, a security scanner designed to detect malicious pickle files. The vulnerability lies in the interaction between two analysis passes: UnsafeImportsML and MLAllowlist. Shared mutable state through the reported_shortened_code set causes MLAllowlist to skip its allowlist check entirely, rendering the pass dead code. As a result, any Python standard library module absent from the UNSAFE_IMPORTS denylist can be invoked through pickle deserialization while check_safety() returns LIKELY_SAFE. The fickling.load() API relies on this verdict as a security gate, allowing malicious payloads to be deserialized and executed. This is tracked under [CWE-693] (Protection Mechanism Failure).
Critical Impact
Attackers can craft pickle payloads that pass fickling safety checks and achieve arbitrary code execution when deserialized by downstream consumers.
Affected Products
- Trail of Bits fickling versions 0.1.0 through 0.1.11
- Applications using fickling.load() as a pickle safety gate
- ML pipelines relying on fickling to vet untrusted model artifacts
Discovery Timeline
- 2026-07-04 - CVE-2026-14535 published to NVD
- 2026-07-06 - Last updated in NVD database
Technical Details for CVE-2026-14535
Vulnerability Analysis
The defect is a protection mechanism failure caused by shared state between two independently correct analysis passes. The UnsafeImportsML pass calls AnalysisContext.shorten_code(node) on every import it inspects, regardless of whether that import is flagged as unsafe. This call registers the shortened code representation in the shared AnalysisContext.reported_shortened_code set. When MLAllowlist later invokes shorten_code() on the same nodes, it receives already_reported=True and executes a continue statement that bypasses the allowlist evaluation entirely. The consequence is that any import outside the ML ecosystem allowlist (torch, numpy, transformers) but not in the UNSAFE_IMPORTS denylist evades detection. Because fickling.load() chains check_safety() into pickle.loads() as an explicit security gate, a LIKELY_SAFE verdict causes the payload to be deserialized and executed by the vulnerable host process.
Root Cause
The root cause is shared mutable state between the UnsafeImportsML and MLAllowlist analysis passes. UnsafeImportsML poisons the deduplication set used by MLAllowlist, turning the allowlist check into unreachable code. Both passes function correctly in isolation but fail when composed.
Attack Vector
An attacker crafts a pickle file that imports a standard library module capable of executing code (for example, subprocess or os) that is neither in UNSAFE_IMPORTS nor in the ML allowlist. The victim application uses fickling.load() or check_safety() to validate the payload before deserialization. Because MLAllowlist never runs, fickling returns LIKELY_SAFE, and the pickle is passed to pickle.loads(), executing the attacker-controlled reduce callable.
# Security patch in fickling/ml.py
# Fix MLAllowlist shadowing (GHSA-cffv-grgg-g429) (#278)
-class MLAllowlist(Analysis):
+class MLAllowlist(Analysis, register=False):
def __init__(self):
super().__init__()
self.allowlist = ML_ALLOWLIST
def analyze(self, context: AnalysisContext) -> Iterator[AnalysisResult]:
for node in context.pickled.properties.imports:
- shortened, already_reported = context.shorten_code(node)
- if already_reported:
- continue
+ shortened = context.shorten_code(node)
if isinstance(node, ast.ImportFrom):
# from module import x
Source: GitHub Commit 41ce7cb
Detection Methods for CVE-2026-14535
Indicators of Compromise
- Pickle files containing imports of standard library modules such as subprocess, os, pty, or runpy that pass fickling safety checks as LIKELY_SAFE.
- Unexpected child processes spawned by Python applications immediately after loading pickle or ML model artifacts.
- ML model files (.pkl, .pt, .pickle) originating from untrusted sources that reference non-ML modules.
Detection Strategies
- Inventory Python environments and identify installed fickling versions using pip show fickling; flag any version at or below 0.1.11.
- Perform static inspection of pickle files with pickletools.dis() to enumerate GLOBAL opcodes and validate imported modules against a strict allowlist independent of fickling.
- Correlate deserialization events with subsequent process creation, network egress, or file writes in application telemetry.
Monitoring Recommendations
- Monitor Python worker processes for execve and fork syscalls occurring within milliseconds of pickle.loads() invocations.
- Alert on outbound network connections from services that load ML artifacts but should not initiate egress traffic.
- Track supply chain integrity of model files by verifying cryptographic signatures before invoking fickling.load().
How to Mitigate CVE-2026-14535
Immediate Actions Required
- Upgrade fickling to version 0.1.12 or later, which unregisters the broken MLAllowlist pass and restores intended safety semantics.
- Audit all code paths that call fickling.load() or check_safety() and confirm the runtime version is patched.
- Treat pickle files from untrusted sources as executable code and require out-of-band signature validation before loading.
Patch Information
The fix is available in fickling0.1.12, released via the GitHub Release v0.1.12. The patch in Pull Request #278 marks MLAllowlist with register=False to prevent the shadowed pass from misreporting safety. Full technical context is documented in GHSA-cffv-grgg-g429.
Workarounds
- Replace fickling.load() with a safer serialization format such as safetensors for ML weights or JSON for structured data.
- If upgrading immediately is not possible, wrap pickle loads in a subprocess sandbox with restricted syscalls and no network access.
- Enforce an explicit allowlist of pickle-importable modules in application code rather than relying solely on fickling verdicts.
# Upgrade fickling to the patched release
pip install --upgrade 'fickling>=0.1.12'
# Verify the installed version
python -c "import fickling; print(fickling.__version__)"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

