Fickling has Static Analysis Bypass via Incomplete Dangerous Module BlocklistGHSA-q5qq-mvfm-j35x
Fix: trailofbits/fickling#195GHSA-q5qq-mvfm-j35x is a CWE-184 vulnerability in fickling. A fix is available for fickling — see the affected versions and patch details below.
Exploitation Status
Proof-of-concept exploit code exists
- CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
- CISA assesses this as automatable — exploitation doesn’t require manual, per-target effort, which raises the odds of mass scanning and opportunistic attacks.
- A successful exploit gives an attacker total control of the affected component, not partial access.
Exploitation and automatability from CISA’s SSVC triage for GHSA-q5qq-mvfm-j35x.
EPSS Exploitation Probability
Probability of exploitation in the next 30 days, from FIRST.org EPSS.
Real-World Exposure
ficklingReal-time download stats are indexed for npm and PyPI packages. This vulnerability affects PyPI packages — download data is not available via public APIs for these ecosystems.
Description
#Fickling's assessment
ctypes, importlib, runpy, code and multiprocessing were added the list of unsafe imports (https://github.com/trailofbits/fickling/commit/9a2b3f89bd0598b528d62c10a64c1986fcb09f66, https://github.com/trailofbits/fickling/commit/eb299b453342f1931c787bcb3bc33f3a03a173f9, https://github.com/trailofbits/fickling/commit/29d5545e74b07766892c1f0461b801afccee4f91, https://github.com/trailofbits/fickling/commit/b793563e60a5e039c5837b09d7f4f6b92e6040d1, https://github.com/trailofbits/fickling/commit/b793563e60a5e039c5837b09d7f4f6b92e6040d1).
Original report
Summary
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.
Details
In fickling/fickle.py lines 866-884, the unsafe_imports() method checks imported modules against a hardcoded tuple:
def unsafe_imports(self) -> Iterator[ast.Import | ast.ImportFrom]:
for node in self.properties.imports:
if node.module in (
"__builtin__", "__builtins__", "builtins", "os", "posix", "nt",
"subprocess", "sys", "builtins", "socket", "pty", "marshal", "types",
):
yield node
This list is incomplete. The following dangerous modules are NOT detected:
- ctypes: Allows arbitrary memory access, calling C functions, and bypassing Python restrictions entirely
- importlib: Can dynamically import any module at runtime
- runpy: Can execute Python modules as scripts
- code: Can compile and execute arbitrary Python code
- multiprocessing: Can spawn processes with arbitrary code
Since ctypes is part of the Python standard library, it also bypasses the NonStandardImports analysis.
PoC
from fickling.fickle import Pickled
from fickling.analysis import check_safety, Severity
# Pickle that imports ctypes.pythonapi (allows arbitrary code execution)
# PROTO 4, GLOBAL 'ctypes pythonapi', STOP
payload = b'\x80\x04cctypes\npythonapi\n.'
pickled = Pickled.load(payload)
results = check_safety(pickled)
print(f"Severity: {results.severity.name}")
print(f"Is safe: {results.severity == Severity.LIKELY_SAFE}")
# Output: Severity is LIKELY_SAFE or low - the ctypes import is not flagged
# A truly malicious pickle using ctypes could execute arbitrary code
Impact
Security Bypass (Confidentiality, Integrity, Availability)
An attacker can craft a malicious pickle that:
- Imports
ctypesto gain arbitrary memory access - Uses
ctypes.pythonapiorctypes.CDLLto execute arbitrary code - Passes Fickling's safety analysis as "likely safe"
- Executes malicious code when the victim loads the pickle after trusting Fickling's verdict
This undermines the core purpose of Fickling as a pickle safety scanner.
Affected Packages
| Ecosystem | Package | Vulnerable range | Fix |
|---|---|---|---|
| 🐍PyPI | fickling | all versions | 0.1.7pip install --upgrade 'fickling==0.1.7' |
Affected Products
ficklingtrailofbitsDetection & mitigation playbook
Open-source dependencyDetect
Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for fickling, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.
Fix
Update fickling to 0.1.7 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-q5qq-mvfm-j35x is resolved across your whole dependency graph.
Workarounds
Do not deserialise data from untrusted sources: where the format allows it, restrict deserialisation to an explicit allowlist of expected types, and prefer a data-only format (JSON, Protobuf) over one that can reconstruct arbitrary objects until you can upgrade.
Frequently Asked Questions
Is GHSA-q5qq-mvfm-j35x in your dependencies?
Find it across PyPI, including transitive dependencies.