Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-14534

CVE-2026-14534: Trail of Bits Fickling RCE Vulnerability

CVE-2026-14534 is a remote code execution vulnerability in Trail of Bits fickling up to version 0.1.10 that allows attackers to bypass security checks. This post covers technical details, affected versions, impact, and mitigation.

Published:

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.

python
         "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
bash
# 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.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.