CVE-2026-14535: fickling: shared-state bug disables ML pickle allowlist check
CRITICAL PoC AVAILABLE CISA: ATTENDFickling, Trail of Bits' pickle-safety scanner for ML model files, has a logic bug where its UnsafeImportsML pass silently poisons a shared deduplication cache, causing the downstream MLAllowlist pass to skip its check on every single import — meaning the allowlist that's supposed to catch modules outside the known-safe ML ecosystem (torch, numpy, transformers, etc.) never actually runs. Any organization relying on fickling.load() as a security gate before deserializing untrusted pickle-based model files gets a false LIKELY_SAFE verdict and proceeds straight into pickle.loads(), enabling arbitrary code execution via any standard library module not explicitly denylisted by UnsafeImports. There's no CISA KEV listing, no EPSS score, and no public exploit or scanner template yet — this reads as a freshly disclosed logic flaw rather than something under active attack — but the CVSS 8.8 (network, low complexity, no privileges, only user interaction) reflects that any team using fickling as a gate for third-party model uploads is currently unprotected against exactly the class of attack the tool exists to stop. Upgrade to fickling >= 0.1.12 immediately, and until upgraded, do not treat a LIKELY_SAFE fickling verdict as sufficient — pair it with sandboxed deserialization or migrate untrusted model ingestion to safetensors.
What is the risk?
High severity (CVSS 8.8) driven by full compromise potential (C:H/I:H/A:H) via network-delivered pickle files, offset only by the requirement for user interaction (someone or some pipeline must trigger fickling.load() on the malicious artifact). No evidence of active exploitation, no EPSS data, and no public PoC or Nuclei template exist yet, so near-term opportunistic exploitation risk is low-to-moderate. However, exploitability is trivial once a payload is crafted, since the flaw is a fail-open logic bug in a security control rather than a hard-to-reach memory corruption bug — any attacker who understands fickling's dual-pass architecture (public since the GHSA advisory and patch commit) can construct a pickle using a standard library import that clears UnsafeImports' denylist and is never checked by the now-dead MLAllowlist pass. The real exposure is organizational: any ML platform, model registry, or MLOps pipeline that gates untrusted pickle uploads with fickling.check_safety()/fickling.load() has been operating with a false sense of security since the bug was introduced, up to and including version 0.1.11.
How does the attack unfold?
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| Fickling | pip | — | No patch |
Do you use Fickling? You're affected.
How severe is it?
What is the attack surface?
What should I do?
1 step-
Upgrade fickling to >= 0.1.12 immediately, which fixes the shared AnalysisContext state issue (see the linked commit and GHSA-cffv-grgg-g429 advisory). Until upgraded, do not treat a fickling LIKELY_SAFE result as a sufficient control on its own — require additional layers such as loading untrusted pickles only inside a disposable sandbox/container with no network egress and least-privilege filesystem access, or better, migrate untrusted model ingestion workflows to a non-executable serialization format like safetensors. For detection, audit CI/CD and MLOps pipeline logs for calls to fickling.load()/check_safety() prior to 0.1.12 usage and treat any artifacts approved during that window as unverified; re-scan historical model artifacts with the patched version. Pin fickling>=0.1.12 in dependency manifests and add a CI check that fails builds on older pinned versions.
What does CISA's SSVC say?
Source: CISA Vulnrichment (SSVC v2.0). Decision based on the CISA Coordinator decision tree.
How is it classified?
Which compliance frameworks are affected?
This CVE is relevant to:
Frequently Asked Questions
What is CVE-2026-14535?
Fickling, Trail of Bits' pickle-safety scanner for ML model files, has a logic bug where its UnsafeImportsML pass silently poisons a shared deduplication cache, causing the downstream MLAllowlist pass to skip its check on every single import — meaning the allowlist that's supposed to catch modules outside the known-safe ML ecosystem (torch, numpy, transformers, etc.) never actually runs. Any organization relying on fickling.load() as a security gate before deserializing untrusted pickle-based model files gets a false LIKELY_SAFE verdict and proceeds straight into pickle.loads(), enabling arbitrary code execution via any standard library module not explicitly denylisted by UnsafeImports. There's no CISA KEV listing, no EPSS score, and no public exploit or scanner template yet — this reads as a freshly disclosed logic flaw rather than something under active attack — but the CVSS 8.8 (network, low complexity, no privileges, only user interaction) reflects that any team using fickling as a gate for third-party model uploads is currently unprotected against exactly the class of attack the tool exists to stop. Upgrade to fickling >= 0.1.12 immediately, and until upgraded, do not treat a LIKELY_SAFE fickling verdict as sufficient — pair it with sandboxed deserialization or migrate untrusted model ingestion to safetensors.
Is CVE-2026-14535 actively exploited?
Proof-of-concept exploit code is publicly available for CVE-2026-14535, increasing the risk of exploitation.
How to fix CVE-2026-14535?
Upgrade fickling to >= 0.1.12 immediately, which fixes the shared AnalysisContext state issue (see the linked commit and GHSA-cffv-grgg-g429 advisory). Until upgraded, do not treat a fickling LIKELY_SAFE result as a sufficient control on its own — require additional layers such as loading untrusted pickles only inside a disposable sandbox/container with no network egress and least-privilege filesystem access, or better, migrate untrusted model ingestion workflows to a non-executable serialization format like safetensors. For detection, audit CI/CD and MLOps pipeline logs for calls to fickling.load()/check_safety() prior to 0.1.12 usage and treat any artifacts approved during that window as unverified; re-scan historical model artifacts with the patched version. Pin fickling>=0.1.12 in dependency manifests and add a CI check that fails builds on older pinned versions.
What systems are affected by CVE-2026-14535?
This vulnerability affects the following AI/ML architecture patterns: model serving, training pipelines, MLOps / model registry ingestion.
What is the CVSS score for CVE-2026-14535?
CVE-2026-14535 has a CVSS v3.1 base score of 9.8 (CRITICAL). The EPSS exploitation probability is 0.33%.
What is the AI security impact?
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0010.003 Model AML.T0011.000 Unsafe AI Artifacts AML.T0018.002 Embed Malware Compliance Controls Affected
What are the technical details?
Original Advisory
In Trail of Bits fickling versions up to and including 0.1.11, the UnsafeImportsML analysis pass unconditionally calls AnalysisContext.shorten_code(node) on every import node it inspects, regardless of whether the import is flagged as unsafe. This call registers the shortened code representation in the shared AnalysisContext.reported_shortened_code set. When the MLAllowlist analysis pass subsequently runs, it calls the same shorten_code() method, receives already_reported=True for every import, and executes a continue statement that skips its allowlist check entirely. This renders MLAllowlist dead code for all imports — it never evaluates whether an import is in the ML allowlist or not. The MLAllowlist pass was designed to catch imports of modules outside the known-safe ML ecosystem (torch, numpy, transformers, etc.) that slip past the UnsafeImports denylist. With MLAllowlist inoperative, any standard library module not in the UNSAFE_IMPORTS denylist can be invoked via pickle deserialization while fickling's check_safety() returns LIKELY_SAFE. The fickling.load() API chains check_safety() into pickle.loads() as an explicit security gate, meaning a LIKELY_SAFE verdict causes the payload to be deserialized and executed. The root cause is shared mutable state between independently-correct analysis passes — UnsafeImportsML works as designed in isolation, MLAllowlist works as designed in isolation, but the shared reported_shortened_code set causes UnsafeImportsML to poison MLAllowlist's deduplication logic.
Exploitation Scenario
An attacker crafts a malicious PyTorch/pickle model file that imports a standard library module absent from fickling's UNSAFE_IMPORTS denylist (rather than an obviously dangerous module like os.system, which would be blocked) and embeds a __reduce__ payload that invokes that module's functionality to achieve code execution on load. The attacker uploads this file to a public model-sharing platform, an internal model registry with an open-upload workflow, or sends it via email/shared drive to a data science team member with a lure ('updated fine-tuned checkpoint'). The victim organization's pipeline runs fickling.load() as its security gate; because UnsafeImportsML has already marked the import as 'reported' via shorten_code(), MLAllowlist silently no-ops and check_safety() returns LIKELY_SAFE, so the file proceeds straight into pickle.loads() and executes the attacker's code with the privileges of the ML pipeline or the data scientist's workstation — potentially pivoting further into training infrastructure, cloud credentials, or the model registry itself.
Weaknesses (CWE)
CWE-693 — Protection Mechanism Failure: The product does not use or incorrectly uses a protection mechanism that provides sufficient defense against directed attacks against the product.
Source: MITRE CWE corpus.
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H References
Timeline
Related Vulnerabilities
CVE-2026-14534 8.8 fickling: denylist gaps let malicious pickles execute
Same package: fickling GHSA-wccx-j62j-r448 fickling: Protection Bypass circumvents security controls
Same package: fickling GHSA-5cxw-w2xg-2m8h fickling: Allowlist Bypass evades input filtering
Same package: fickling GHSA-r48f-3986-4f9c fickling: Allowlist Bypass evades input filtering
Same package: fickling GHSA-5hwf-rc88-82xm fickling: Allowlist Bypass evades input filtering
Same package: fickling