CVE-2026-14534 Overview
CVE-2026-14534 affects Trail of Bits fickling versions up to and including 0.1.10. The library's UNSAFE_IMPORTS denylist in fickle.py omits three Python standard library modules: _posixsubprocess, site, and atexit. As a result, the check_safety() function returns LIKELY_SAFE for pickle payloads that invoke dangerous callables from these modules. Because fickling.load() uses check_safety() as an explicit security gate before calling pickle.loads(), a malicious payload can bypass the scanner and execute arbitrary code during deserialization. The flaw is classified under [CWE-184: Incomplete List of Disallowed Inputs].
Critical Impact
Attackers can craft pickle files that pass fickling's safety check and execute arbitrary binaries via _posixsubprocess.fork_exec, arbitrary code via site.execsitecustomize, or registered exit handlers via atexit._run_exitfuncs.
Affected Products
- Trail of Bits fickling versions 0.1.0 through 0.1.10
- Python applications relying on fickling.load() for safe pickle deserialization
- ML pipelines using fickling to scan model files before loading
Discovery Timeline
- 2026-07-04 - CVE-2026-14534 published to NVD
- 2026-07-06 - Last updated in NVD database
- v0.1.11 - Trail of Bits releases patched fickling version
Technical Details for CVE-2026-14534
Vulnerability Analysis
The fickling library statically analyzes pickle bytecode and applies heuristics to determine whether deserialization is safe. Its UNSAFE_IMPORTS denylist enumerates Python modules whose imports should trigger a warning. The list omits _posixsubprocess, site, and atexit, all of which expose callables capable of arbitrary code execution.
A crafted pickle payload can reference _posixsubprocess.fork_exec to spawn arbitrary processes at the C level. Alternatively, site.execsitecustomize executes arbitrary site customization code, and atexit._run_exitfuncs triggers all registered exit handler callbacks. The OvertlyBadEvals heuristic does not flag these calls because the modules are standard library imports. The UnusedVariables heuristic is defeated by using the SETITEMS opcode pattern.
This vulnerability shares its root cause with CVE-2026-22607 (cProfile), CVE-2025-67748 (pty), and CVE-2025-67747 (marshal/types).
Root Cause
The root cause is an incomplete denylist [CWE-184]. fickling's security model relies on enumerating dangerous imports rather than allowlisting known-safe ones. Any standard library module missing from UNSAFE_IMPORTS bypasses the safety check entirely.
Attack Vector
An attacker distributes a malicious pickle file, for example, a serialized ML model. When a victim application loads the file with fickling.load(), check_safety() returns LIKELY_SAFE with zero findings. The library then calls pickle.loads(), invoking the attacker-controlled callable during unpickling and executing arbitrary code in the victim process.
"pty",
"commands", # Legacy Python 2 module
"multiprocessing",
+ "_posixsubprocess",
# Code execution/compilation
"code",
"codeop",
Source: GitHub Commit e840861 — the patch adds _posixsubprocess (and additional modules) to the UNSAFE_IMPORTS blocklist so check_safety() returns a warning verdict for payloads referencing them.
Detection Methods for CVE-2026-14534
Indicators of Compromise
- Pickle files containing GLOBAL or STACK_GLOBAL opcodes referencing _posixsubprocess, site, or atexit
- Unexpected child processes spawned by Python interpreters loading pickle files
- Presence of SETITEMS opcode sequences immediately preceding calls into standard library modules
- Pickle payloads that pass fickling.check_safety() yet trigger process creation or exit handler registration
Detection Strategies
- Statically scan pickle files for references to _posixsubprocess.fork_exec, site.execsitecustomize, and atexit._run_exitfuncs regardless of fickling's verdict
- Monitor Python processes that call pickle.loads() for subsequent execve or fork syscalls
- Audit installed fickling versions across the environment and flag any release at or below 0.1.10
Monitoring Recommendations
- Log all invocations of fickling.load() and fickling.check_safety() alongside the source of the input file
- Alert when Python worker processes in ML pipelines spawn shell interpreters or network utilities
- Track outbound network connections from processes that recently deserialized untrusted pickle data
How to Mitigate CVE-2026-14534
Immediate Actions Required
- Upgrade fickling to version 0.1.11 or later across all environments
- Inventory ML pipelines, CI runners, and services that ingest third-party pickle or model files
- Treat any pickle scanned by an unpatched fickling as untrusted and rescan with the patched version
- Restrict deserialization of pickle files to trusted, signed sources only
Patch Information
Trail of Bits released fickling v0.1.11 via Pull Request #272, addressing GHSA-m6fh-58r7-x697. The fix expands the UNSAFE_IMPORTS denylist in fickle.py to include _posixsubprocess, site, atexit, and related modules so that check_safety() returns a warning verdict for payloads referencing them.
Workarounds
- Avoid loading pickle files from untrusted sources; prefer safer serialization formats such as JSON, Protocol Buffers, or safetensors for ML models
- Run pickle deserialization in sandboxed environments with seccomp or containerized isolation that blocks execve and fork
- Manually extend UNSAFE_IMPORTS in fickle.py to include _posixsubprocess, site, and atexit if upgrading immediately is not possible
# Upgrade fickling to the patched release
pip install --upgrade 'fickling>=0.1.11'
# 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.

