CVE-2026-14534: Unsafe Pickle Validation Bypass
| Field | Value |
|---|---|
| CVE ID | CVE-2026-14534 |
| CVSS score | 8.8 |
| Attack vector | Network/remote delivery is plausible via untrusted pickle input |
| Auth required | Unknown; assume no meaningful protection if untrusted pickle content can reach the application |
| Patch status | Fixed in fickling v0.1.11 |
TL;DR -
ficklingthrough0.1.10misclassifies malicious pickle payloads as safe. - Upgrade to0.1.11immediately if usingfickling.load()on untrusted data. - No confirmed exploitation or public PoC identified, but code execution risk is urgent.
What is CVE-2026-14534?
CVE-2026-14534 is an insecure deserialization defense bypass in Trail of Bits fickling, a Python pickle decompiler and static analyzer used to inspect or gate pickle payloads before deserialization. Versions up to and including 0.1.10 failed to classify three dangerous Python standard library modules as unsafe imports: _posixsubprocess, site, and atexit.
This is significant because fickling has a safety workflow where check_safety() evaluates a pickle stream before fickling.load() proceeds to deserialization. In vulnerable versions, a crafted payload can lead check_safety() to return LIKELY_SAFE with no findings, allowing the payload to reach dangerous functions like _posixsubprocess.fork_exec, site.execsitecustomize, or atexit._run_exitfuncs. If an application trusts this result and calls pickle.loads(), attacker-controlled code may execute.
This is not a bug in Python pickle itself; pickle is inherently unsafe for untrusted input. The problem lies in the bypassing of a defensive control meant to reduce that risk. Security teams must recognize that environments relying on a safe inspection gate for untrusted pickle data may need to reevaluate their trust assumptions.
The fixed version is v0.1.11, which updates the analyzer logic to ensure these omitted modules are no longer allowed through the safety gate.
Who is affected?
The affected product is Trail of Bits fickling, specifically versions up to and including 0.1.10. The first fixed release is 0.1.11.
Exposure is highest where fickling is used to assess untrusted pickle content. This includes workflows that ingest machine learning artifacts, cached objects, or any user-supplied files that flow into a fickling.load() path. If your application accepts pickle data from external sources without proper controls, treat this as potentially exploitable.
Even if your software does not directly expose pickle upload functionality, indirect exposure matters. Internal tools, model registries, and automated workflows may use fickling to determine whether a pickle blob is safe. Such workflows can become a code execution path if they trust vulnerable versions.
If you are unsure whether your organization uses fickling, assume it may be present anywhere Python security tooling exists. Search for fickling references in requirements files, lockfiles, and container images.
Why this vulnerability matters operationally
The severity score of 8.8 indicates the potential for arbitrary code execution if untrusted pickle input is allowed. The operational issue is that the security control intended to prevent dangerous payloads can create a false sense of safety, increasing the likelihood of risky behavior.
The NVD description details the failure mode. OvertlyBadEvals did not flag these imports because they are standard library modules. The UnsafeImports list was incomplete, allowing dangerous modules to pass undetected. Multiple heuristics failed to catch a malicious payload when specific modules and opcode patterns were used together.
For defenders, this means risk should be framed as control bypass leading to code execution, not merely a scanner failure. If your process states “run fickling and load the file if it looks safe,” the vulnerable logic may have allowed hostile input to execute. Immediate patching and retrospective review are essential.
Exploitation status and what to assume
As of now, no confirmed exploitation in the wild has been reported. The CVE is not listed in CISA KEV as of 2026-07-04, and there is no standalone public PoC confirmed.
However, the absence of a confirmed PoC does not imply low risk. The vulnerability description is actionable, identifying dangerous modules and functions involved. For experienced users, this information is often sufficient to build a working proof of concept quickly. Thus, while no public PoC exists today, the path to weaponization is clear.
For defenders, the stance should be: no confirmed active exploitation, no verified public PoC, but strong exploitability indicators based on the published root cause. If you run fickling in a high-exposure workflow, prioritize remediation as if a PoC could emerge at any time.
Bottom line for defenders
If you run Trail of Bits fickling 0.1.10 or earlier, and you use it to decide whether pickle content is safe to load, treat that trust decision as unreliable until you upgrade to 0.1.11. The impact is potentially severe due to the failure mode leading directly to deserialization of attacker-controlled data.
Even without confirmed exploitation or a verified public PoC, this issue deserves fast remediation. Patch the package, review code paths that call fickling.load(), and revisit any workflow that assumes pickle can be made safe through a single static screening step.
For more information on securing your applications, consider reading about how to build a practical vulnerability management program or check the latest on CVE-2026-43633.
This article may contain affiliate links. We earn a commission on qualifying purchases at no extra cost to you.
How to detect exposure
Start with asset and dependency discovery. Identify whether fickling is installed and if the version is 0.1.10 or earlier. Determine if your codebase uses fickling.load(), check_safety(), or any wrapper that treats LIKELY_SAFE as permission to deserialize untrusted input.
Repository and filesystem reviews are often more reliable than waiting for runtime telemetry. Search Python projects, containers, and virtual environments for explicit imports and pinned dependency versions. If you find fickling==0.1.10 or earlier, review the call path around pickle handling immediately.
Technical Notes
Check installed version:
python -m pip show fickling
python -m pip freeze | grep -i '^fickling=='
pip3 freeze | grep -i '^fickling=='
Search code for potentially risky usage:
grep -RIn "fickling\.load\|check_safety\|pickle\.loads\|pickle\.load" .
Look for dependency declarations pinning affected versions:
grep -RIn "fickling" requirements*.txt pyproject.toml poetry.lock Pipfile* setup.cfg setup.py
Concrete log and detection ideas:
If you have Python application logs around safety checks, look for sequences where a payload was marked safe immediately before deserialization. Patterns like the following are worth reviewing:
check_safety verdict=LIKELY_SAFE findings=0
fickling.load invoked
pickle.loads(...)
If you log process creation from Python services, look for suspicious child processes spawned by services that should only parse data. Since _posixsubprocess.fork_exec is explicitly called out, endpoint telemetry showing unexpected child execution from a pickle-processing service is a significant indicator.
Example Splunk query for Python services that log safety checks and then spawn processes:
index=app_logs ("LIKELY_SAFE" OR "check_safety") OR index=edr_logs process_name=python*
| transaction host maxspan=5m
| search ("LIKELY_SAFE" AND ("fork_exec" OR "execsitecustomize" OR "atexit" OR "child_process" OR "process_start"))
If you do not have application logs for fickling, assume visibility is limited. Prioritize dependency discovery, code review, and EDR process telemetry around systems that deserialize pickle content.
Mitigation and patching
The primary mitigation is to upgrade from affected versions up to and including 0.1.10 to 0.1.11. If fickling is installed from PyPI, update the package directly and redeploy the environment. Ensure your lockfiles and build pipelines also pin the corrected version to avoid reintroducing the vulnerable release.
If immediate patching is not possible, the safest workaround is to stop treating fickling as a sufficient security gate for untrusted pickle content. This means do not deserialize untrusted pickle data at all, even when check_safety() returns LIKELY_SAFE. Quarantine inbound pickle files, require provenance validation, or switch to a safer serialization format.
A temporary defense-in-depth step is to add a policy layer that rejects payloads referencing _posixsubprocess, site, or atexit, and to disable or isolate any automated processing pipeline that loads external pickle blobs. Remember, this is a workaround, not a replacement for patching, as denylist-based controls should not be the only protection.
Technical Notes
Upgrade command:
python -m pip install --upgrade "fickling==0.1.11"
If you manage dependencies via a requirements file:
sed -i.bak 's/^fickling==.*/fickling==0.1.11/' requirements.txt
python -m pip install -r requirements.txt
If you need an immediate code-level workaround, block deserialization when safety results are the only control:
from fickling import check_safety
import pickle
def reject_untrusted_pickle(data: bytes):
result = check_safety(data)
# Temporary hardening: do not trust a positive verdict as permission to load.
raise RuntimeError(
"Untrusted pickle deserialization disabled until fickling is upgraded to 0.1.11+"
)
# Do not call pickle.loads(data) on untrusted input.
Operational workaround: - Disable upload or ingestion paths for pickle artifacts from untrusted sources. - Restrict egress and process spawning on systems that must temporarily inspect pickle data. - Rebuild containers and serverless packages after updating the dependency, not just the source tree.
References
The following references are associated with this vulnerability and remediation:
| Reference | URL |
|---|---|
| Commit | GitHub Commit |
| Pull request | GitHub Pull Request |
| Fixed release | GitHub Release |
| Security advisory | GitHub Security Advisory |
The NVD record is the authoritative public source for the vulnerability summary used here. Some details such as the exact CVSS vector and confirmed exploitation telemetry were not available in the provided source data.