CVE-2026-14534: fickling: denylist gaps let malicious pickles execute
HIGH PoC AVAILABLE CISA: ATTENDFickling is Trail of Bits' security gate meant to block malicious pickle files before they're deserialized, but its denylist omits three standard-library modules — _posixsubprocess, site, and atexit — that a crafted pickle can invoke to spawn arbitrary processes, run injected code, or trigger callback execution, and check_safety() waves the payload through as LIKELY_SAFE with zero findings. This matters because any pipeline that trusts fickling.load() as a gatekeeper before loading a downloaded model checkpoint or dataset pickle now has a false sense of security — a poisoned .pkl or .pt file disguised as a legitimate model can achieve full remote code execution the moment it's loaded, and the CVSS 8.8 score (AV:N/AC:L/PR:N) reflects how low the bar is once a victim is convinced to open the file. There's no CISA KEV listing, no public exploit, and no EPSS data yet, so this hasn't been weaponized in the wild, but the pattern is now public and is the fourth in a series with the same root cause (CVE-2026-22607, CVE-2025-67748, CVE-2025-67747), meaning it's trivially generalizable to the next unlisted stdlib module. Patch to fickling 0.1.11 immediately in any model-scanning or CI/CD ingestion pipeline, and stop treating a LIKELY_SAFE verdict from fickling as a substitute for sandboxed execution of untrusted pickle files.
What is the risk?
High severity (CVSS 8.8) but not yet weaponized: no CISA KEV entry, no public exploit code, and no EPSS score, so real-world exploitation likelihood is currently unknown/low. However, exploitability is straightforward for anyone who understands pickle internals — attack complexity is LOW and no privileges are required, only user interaction (the victim's pipeline calling fickling.load() on the malicious file). The real risk driver is scope: this isn't a flaw in a random package, it's a flaw in the security control organizations adopted specifically to make pickle deserialization safe, so the exposure is concentrated in teams that made a deliberate, security-conscious choice to use fickling and now have a false sense of protection. Impact is maximal (C:H/I:H/A:H) since successful exploitation is full arbitrary code execution on the host performing the deserialization.
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.11 or later immediately, which adds _posixsubprocess, site, and atexit to the UNSAFE_IMPORTS denylist (see commit e8408615 and PR #272). Do not treat any fickling version's LIKELY_SAFE verdict as sufficient on its own — pair it with sandboxed/isolated deserialization (containers, gVisor, restricted seccomp profiles) for any pickle originating outside your organization. Where feasible, migrate model storage to non-executable formats like safetensors instead of pickle to eliminate this class of risk entirely. For detection, audit logs/EDR for anomalous child-process spawns or unexpected site-customization/exit-handler execution originating from Python processes that load ML artifacts, and flag any pickle payload containing SETITEMS-heavy opcode sequences during ingestion.
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-14534?
Fickling is Trail of Bits' security gate meant to block malicious pickle files before they're deserialized, but its denylist omits three standard-library modules — _posixsubprocess, site, and atexit — that a crafted pickle can invoke to spawn arbitrary processes, run injected code, or trigger callback execution, and check_safety() waves the payload through as LIKELY_SAFE with zero findings. This matters because any pipeline that trusts fickling.load() as a gatekeeper before loading a downloaded model checkpoint or dataset pickle now has a false sense of security — a poisoned .pkl or .pt file disguised as a legitimate model can achieve full remote code execution the moment it's loaded, and the CVSS 8.8 score (AV:N/AC:L/PR:N) reflects how low the bar is once a victim is convinced to open the file. There's no CISA KEV listing, no public exploit, and no EPSS data yet, so this hasn't been weaponized in the wild, but the pattern is now public and is the fourth in a series with the same root cause (CVE-2026-22607, CVE-2025-67748, CVE-2025-67747), meaning it's trivially generalizable to the next unlisted stdlib module. Patch to fickling 0.1.11 immediately in any model-scanning or CI/CD ingestion pipeline, and stop treating a LIKELY_SAFE verdict from fickling as a substitute for sandboxed execution of untrusted pickle files.
Is CVE-2026-14534 actively exploited?
Proof-of-concept exploit code is publicly available for CVE-2026-14534, increasing the risk of exploitation.
How to fix CVE-2026-14534?
Upgrade fickling to 0.1.11 or later immediately, which adds _posixsubprocess, site, and atexit to the UNSAFE_IMPORTS denylist (see commit e8408615 and PR #272). Do not treat any fickling version's LIKELY_SAFE verdict as sufficient on its own — pair it with sandboxed/isolated deserialization (containers, gVisor, restricted seccomp profiles) for any pickle originating outside your organization. Where feasible, migrate model storage to non-executable formats like safetensors instead of pickle to eliminate this class of risk entirely. For detection, audit logs/EDR for anomalous child-process spawns or unexpected site-customization/exit-handler execution originating from Python processes that load ML artifacts, and flag any pickle payload containing SETITEMS-heavy opcode sequences during ingestion.
What systems are affected by CVE-2026-14534?
This vulnerability affects the following AI/ML architecture patterns: model serving, training pipelines, MLOps pipelines, model supply chain / registries.
What is the CVSS score for CVE-2026-14534?
CVE-2026-14534 has a CVSS v3.1 base score of 8.8 (HIGH). The EPSS exploitation probability is 0.37%.
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 AML.T0050 Command and Scripting Interpreter AML.T0058 Publish Poisoned Models Compliance Controls Affected
What are the technical details?
Original Advisory
Trail of Bits fickling versions up to and including 0.1.10 do not include the Python standard library modules _posixsubprocess, site, and atexit in the UNSAFE_IMPORTS denylist (fickle.py). Because these modules are absent from the denylist, fickling's check_safety() function returns LIKELY_SAFE with zero findings for pickle payloads that invoke dangerous functions including _posixsubprocess.fork_exec (C-level process spawner capable of executing arbitrary binaries), site.execsitecustomize (executes arbitrary site customization code), and atexit._run_exitfuncs (triggers all registered exit handler callbacks). The fickling.load() API chains check_safety() into pickle.loads() as an explicit security gate; a LIKELY_SAFE verdict causes the payload to be deserialized and executed. This shares the same root cause as CVE-2026-22607 (cProfile), CVE-2025-67748 (pty), and CVE-2025-67747 (marshal/types). OvertlyBadEvals does not flag these modules because they are standard library imports. UnsafeImports does not flag them because they are not in the denylist. The UnusedVariables heuristic is defeated by the SETITEMS opcode pattern.
Exploitation Scenario
An adversary crafts a malicious pickle file disguised as a fine-tuned model checkpoint, embedding a payload that uses the SETITEMS opcode pattern to defeat fickling's UnusedVariables heuristic while invoking _posixsubprocess.fork_exec (or site.execsitecustomize / atexit._run_exitfuncs) to execute an arbitrary binary or reverse shell. They publish the file to a public model hub or send it directly to a target organization as a 'community fine-tune'. The victim's automated ingestion pipeline calls fickling.load() as a security gate; check_safety() misses the payload because the invoked modules aren't in the denylist, returns LIKELY_SAFE, and the pipeline proceeds to pickle.loads() the file — executing the attacker's code on the training or serving host, potentially exposing cloud credentials, training data, or providing a foothold for lateral movement.
Weaknesses (CWE)
CWE-184 Incomplete List of Disallowed Inputs CWE-184 Incomplete List of Disallowed Inputs CWE-502 Deserialization of Untrusted Data CWE-502 Deserialization of Untrusted Data CWE-184 — Incomplete List of Disallowed Inputs: The product implements a protection mechanism that relies on a list of inputs (or properties of inputs) that are not allowed by policy or otherwise require other action to neutralize before additional processing takes place, but the list is incomplete.
- [Implementation] Do not rely exclusively on detecting disallowed inputs. There are too many variants to encode a character, especially when different environments are used, so there is a high likelihood of missing some variants. Only use detection of disallowed inputs as a mechanism for detecting suspicious activity. Ensure that you are using other protection mechanisms that only identify "good" input - such as lists of allowed inputs - and ensure that you are properly encoding your outputs.
Source: MITRE CWE corpus.
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H References
Timeline
Related Vulnerabilities
CVE-2026-14535 9.8 fickling: shared-state bug disables ML pickle allowlist check
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