CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



GHSA-R48F-3986-4F9C
7.8

GHSA-R48F-3986-4F9C: Security Bypass via Incomplete Blocklist and AST Traversal Flaws in Fickling

Alon Barad
Alon Barad
Software Engineer

Mar 13, 2026·7 min read·4 visits

PoC Available

Executive Summary (TL;DR)

Fickling versions prior to 0.1.10 fail to detect malicious Python pickles due to an incomplete module blocklist and a flaw in AST node traversal, allowing arbitrary code execution or arbitrary file read bypasses.

The Trail of Bits fickling library, a static analyzer and decompiler for Python pickles, suffers from a security bypass vulnerability. Prior to version 0.1.10, the tool failed to include highly privileged standard library modules in its internal blocklist and improperly constructed Abstract Syntax Tree (AST) nodes during analysis. This allows an attacker to craft malicious pickle files that evade detection and subsequently execute arbitrary code or read sensitive files when deserialized by the victim.

Vulnerability Overview

The trailofbits/fickling tool operates as a static analyzer and decompiler for Python pickle files. Its primary design objective is to evaluate serialized data structures and detect overt indicators of malicious behavior before a user passes the data to the inherently unsafe pickle.load() function. The tool decompiles the pickle bytecode into an Abstract Syntax Tree (AST) and flags instances where the serialized object attempts to import known dangerous modules or execute restricted functions.

This vulnerability fundamentally undermines the static analysis capabilities of the tool. It manifests through two distinct but complementary failure conditions within the codebase. First, the explicit blocklist utilized by the analyzer omits several standard library modules capable of altering system state or disclosing information. Second, the internal logic responsible for traversing the decompiled AST contains structural flaws that hide nested operations from the analyzer.

When a malicious actor combines these oversights, they can construct a serialized payload that completely bypasses the security gates of the fickling library. The application will evaluate the deeply nested, unlisted malicious imports and return a "Safe" or "Suspicious" disposition. A system relying on this disposition will subsequently deserialize the payload, triggering the execution of the embedded exploit.

Root Cause Analysis

The first root cause exists within fickling/fickle.py in the declaration of the UNSAFE_IMPORTS set. The fickling static analyzer uses this variable as a definitive list of forbidden module imports. If an AST node attempts to import a module found within this set, the tool assigns the object an OVERTLY_MALICIOUS severity rating. Prior to version 0.1.10, this set omitted critical standard library modules, most notably linecache, difflib, and gc.

The linecache module provides the getlines() function, which an attacker can invoke to perform arbitrary file reads across the filesystem. The difflib module exposes the Differ class, which can be manipulated via the pickle BUILD opcode to store the results of unauthorized function calls within object state variables. The gc (garbage collector) module allows an attacker to access internal memory references, facilitating the discovery of active handles to other unsafe modules.

The second root cause involves a structural logic error in how fickling constructs AST nodes for specific pickle opcodes. When decompiling opcodes such as TupleThree, the tool initializes an ast.Tuple node and assigns a Python tuple to the elts (elements) attribute instead of a Python list. The standard library AST traversal functions, specifically ast.walk and ast.iter_child_nodes, strictly require the elts attribute to be a list. When the traversal logic encounters the improperly structured tuple, it silently terminates traversal for that branch, rendering all child nodes invisible to the security checks.

Code Analysis

The official patch addresses the incomplete blocklist by expanding the explicitly defined UNSAFE_IMPORTS set within the fickling/fickle.py source file. The following unified diff illustrates the exact additions made by the maintainers in commit 7f39d97258217ee2c21a1f5031d4a6d7343eb30d.

# fickling/fickle.py
 UNSAFE_IMPORTS = {
     "os",
     "subprocess",
     "sys",
     "pty",
     "pkgutil",
     "zipimport",
+    "gc",
     "pdb",
     "runpy",
     "platform",
+    "linecache",
+    "difflib",
     "trace",
     "timeit",
 }

While adding these modules to the blocklist mitigates the immediate vectors associated with file read and memory manipulation, the AST traversal flaw highlights a systemic issue in object initialization. In Python's ast module, a tuple node must be constructed with a list of elements. The vulnerable fickling implementation used ast.Tuple(elts=(node1, node2, node3)) instead of ast.Tuple(elts=[node1, node2, node3]).

Additionally, the patch analysis reveals a secondary AST logic flaw in the unused_assignments check. The iteration loop breaks prematurely upon encountering a variable named result. This early break prevents the analyzer from inspecting the right-hand side (RHS) of the assignment. An attacker can assign a malicious function call to the variable result to evade structural detection.

Exploitation

An attacker initiates the exploitation sequence by constructing a highly specific pickle file using the raw pickle opcodes. The attacker avoids commonly flagged modules like os or subprocess and instead leverages the GLOBAL opcode to import linecache.getlines. The attacker then supplies a target file path, such as /etc/passwd or /app/config.json, as the argument to this function.

To ensure the payload bypasses the structural checks within fickling, the attacker wraps the functional execution within a TUPLE3 (or similar) opcode. This forces the fickling decompiler to generate the improperly initialized ast.Tuple node. The attacker then structures the pickle byte stream to assign the output of the file read operation to a persistent variable or object state using the BUILD opcode.

When the security system pipes this byte stream through fickling, the linecache module circumvents the UNSAFE_IMPORTS filter. Subsequently, the ast.walk function hits the ast.Tuple node, encounters the type mismatch on the elts attribute, and aborts branch traversal. The analyzer completes its run without evaluating the malicious child nodes and issues a "Safe" verdict. The host application, trusting the security gate, executes pickle.load() on the payload, which triggers the file read and stores the data into the instantiated object for exfiltration.

Impact Assessment

The impact of this vulnerability is functionally equivalent to arbitrary remote code execution or arbitrary file read, contingent strictly on the access privileges of the application performing the deserialization. Because the vulnerability neutralizes the primary security control (fickling), the impact maps directly to the intrinsic dangers of untrusted Python deserialization.

The CVSS vector evaluates to CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H with a base score of 7.8. The attack vector is Local or Network-adjacent depending on how the application receives the pickle file, but requires User Interaction (UI:R) because a victim process must actively pass the malicious data through the analyzer and then load it. Once loaded, the impact to Confidentiality, Integrity, and Availability is High.

Applications utilizing fickling as an automated gating mechanism in data pipelines or machine learning model ingestion pipelines are severely compromised. If an enterprise assumes that a "Safe" rating from fickling guarantees the structural safety of a .pkl or .pt (PyTorch) file, attackers can silently establish persistence or extract sensitive training data and internal credentials.

Remediation

Organizations utilizing the trailofbits/fickling library must immediately update their dependencies to version 0.1.10. The maintainers successfully deployed patches that expand the UNSAFE_IMPORTS blocklist and address the specific module omissions. Verify the currently installed version using standard package management inspection commands.

The structural limitations of statically analyzing dynamic serialization formats require a defense-in-depth approach. Fickling provides heuristic analysis and is not a definitive security boundary. Developers must treat all unauthenticated pickle files as inherently malicious, regardless of the output generated by static analysis tools.

To permanently eliminate this vulnerability class, migrate data storage and transmission architectures to fundamentally safe formats such as JSON, Protocol Buffers, or MessagePack. If business requirements necessitate the use of the Python pickle format, enforce strict cryptographic provenance using HMAC signatures. The application must verify the cryptographic signature against a trusted public key or shared secret before passing the byte stream to fickling or pickle.load().

Official Patches

Trail of BitsOfficial fix commit addressing the blocklist omission and AST structure logic
Trail of BitsRelease Notes for version 0.1.10

Fix Analysis (1)

Technical Appendix

CVSS Score
7.8/ 10
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H

Affected Systems

trailofbits/ficklingPython Applications relying on Fickling for pickle security

Affected Versions Detail

Product
Affected Versions
Fixed Version
fickling
Trail of Bits
< 0.1.100.1.10
AttributeDetail
Vulnerability TypeSecurity Bypass / Deserialization of Untrusted Data
CWE IDCWE-184, CWE-502
CVSS v3.1 Score7.8 (High)
Affected Componentfickle.py (UNSAFE_IMPORTS), AST node initialization
Exploit StatusProof of Concept (PoC) available
Attack VectorCrafted Pickle Bytecode
Fix Version0.1.10

MITRE ATT&CK Mapping

T1059Command and Scripting Interpreter
Execution
T1190Exploit Public-Facing Application
Initial Access
T1005Data from Local System
Collection
T1592Gather Victim Host Information
Reconnaissance
CWE-184
Incomplete List of Disallowed Inputs

The product does not adequately specify or enforce a complete list of unauthorized or disallowed inputs, allowing bypass of security checks.

Vulnerability Timeline

Vulnerability fixed in source repository (Commit 7f39d97)
2026-03-13
Public Disclosure and Advisory Published
2026-03-01

References & Sources

  • [1]GitHub Security Advisory: GHSA-R48F-3986-4F9C
  • [2]Trail of Bits Fickling Repository

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.