CVE-2026-14535
HighCVSS 8.8Exploitation Probability (EPSS)
Low risk47th percentile - higher than 47% of all known CVEs
Summary
In fickling up to version 0.1.11, the UnsafeImportsML analysis pass registers shortened code for every import in a shared set, causing the subsequent MLAllowlist pass to skip all checks as already reported. This renders MLAllowlist dead code, allowing imports of modules outside the allowlist (e.g., torch, numpy) to be missed, leading to a false LIKELY_SAFE verdict.
Risk Assessment
The organization may be misled by a falsely safe check_safety() result, enabling deserialization of a malicious pickle payload and potential arbitrary code execution by an attacker.
Recommendation
Immediately update fickling to version 0.1.12 or later, which removes the shared state between analysis passes. Until updated, avoid using fickling.load() with untrusted data.
Other vulnerabilities in fickling
See all- CVE-2026-22612High
Fickling, a Python pickling decompiler and static analyzer, before version 0.1.7 contains a vulnerability that allows bypassing detection of malicious code. The issue stems from a lack of analysis of 'builtins' objects and has been fixed in version 0.1.7.
- CVE-2026-22609High
Fickling is a Python pickling decompiler and static analyzer. Prior to version 0.1.7, the unsafe_imports() method in Fickling's static analyzer fails to flag several high-risk Python modules that can be used for arbitrary code execution. Malicious pickles importing these modules will not be detected as unsafe, allowing attackers to bypass Fickling's primary static safety checks.
- CVE-2026-22608High
Fickling is a Python pickling decompiler and static analyzer. Prior to version 0.1.7, it did not explicitly block the ctypes and pydoc modules, which combined with pydoc.locate can achieve RCE while the scanner still reports the file as LIKELY_SAFE. This issue has been patched in version 0.1.7.
- CVE-2026-22607High
Fickling versions up to and including 0.1.6 do not treat Python's cProfile module as unsafe. A malicious pickle using cProfile.run() is classified as SUSPICIOUS instead of OVERTLY_MALICIOUS, potentially leading to arbitrary code execution.
- CVE-2026-22606High
Fickling versions up to and including 0.1.6 do not treat Python's runpy module as unsafe. A malicious pickle using runpy.run_path() or runpy.run_module() is classified as SUSPICIOUS instead of OVERTLY_MALICIOUS. This can lead to arbitrary code execution if users rely on Fickling's output for deserialization safety.
- CVE-2026-16760High
fickling through 0.1.12 incorrectly treats calls to functions from Python standard library modules as safe without inspecting their actual behavior. As a result, check_safety() returns LIKELY_SAFE for malicious pickle payloads that reach code execution or file writes through such callables (e.g., dataclasses._create_fn, mailcap.findmatch, readline.write_history_file). Because fickling.load() uses this verdict as a security gate before pickle.loads(), the payload is deserialized and executed with the privileges of the victim process.
- CVE-2026-118938High
A vulnerability in Trail of Bits fickling through 0.1.12 allows a pickle STACK_GLOBAL operand with a dotted __qualname__ (e.g., "Values.read_file") to be resolved by pickle's find_class via _getattribute to an arbitrary attribute path instead of a module-level function. Fickling records only the leading component in its import tracking and renders the operation as a plain import, so the trailing attribute reference is never analyzed as a call; the OvertlyBadEvals pass does not flag it and check_safety() returns LIKELY_SAFE with zero findings. This lets an attacker reach a class method that performs code execution (optparse.Values.read_file executes exec(open(filename).read(), vars)), achieving arbitrary code execution when the crafted pickle is loaded through fickling.load(), which chains check_safety() into pickle.loads() as an explicit security gate.
- CVE-2026-14534High
The vulnerability in fickling up to version 0.1.10 is due to missing Python standard library modules (_posixsubprocess, site, atexit) in the UNSAFE_IMPORTS denylist. This causes check_safety() to incorrectly mark malicious pickle payloads as LIKELY_SAFE, allowing deserialization and execution of dangerous functions like fork_exec, execsitecustomize, or _run_exitfuncs.
- CVE-2025-67748High
Fickling is a Python pickling decompiler and static analyzer. Versions prior to 0.1.6 had a bypass caused by `pty` missing from the block list of unsafe module imports. This led to unsafe pickles based on `pty.spawn()` being incorrectly flagged as `LIKELY_SAFE`, and was fixed in version 0.1.6. This impacted any user or system that used Fickling to vet pickle files for security issues.
- CVE-2025-67747High
Fickling is a Python pickling decompiler and static analyzer. Versions prior to 0.1.6 are missing `marshal` and `types` from the block list of unsafe module imports. Fickling started blocking both modules to address this issue. This allows an attacker to craft a malicious pickle file that can bypass fickling since it misses detections for `types.FunctionType` and `marshal.loads`. A user who deserializes such a file, believing it to be safe, would inadvertently execute arbitrary code on their system. This impacts any user or system that uses Fickling to vet pickle files for security issues. The issue was fixed in version 0.1.6.
Original NVD description (English source)
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.
Vulnerability data from NVD (NIST) · CISA KEV · EPSS

