High severityOSV Advisory· Published Jan 10, 2026· Updated Jan 13, 2026
Fickling vulnerable to use of ctypes and pydoc gadget chain to bypass detection
CVE-2026-22608
Description
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.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
ficklingPyPI | < 0.1.7 | 0.1.7 |
Affected products
1- Range: master, v0.0.1, v0.0.2, …
Patches
2d0b00d584afbSimplify test case for GHSA-5hvc-6wx8-mvv4 so it doesn't import Exception
1 file changed · +16 −19
test/test_bypasses.py+16 −19 modified@@ -191,28 +191,25 @@ def test_missing_ctypes(self): def test_missing_pydoc(self): pickled = Pickled( [ - op.Global("pydoc locate"), - op.String("ctypes.windll.kernel32.WinExec"), + op.Proto.create(5), + op.ShortBinUnicode("pydoc"), + op.Memoize(), + op.ShortBinUnicode("locate"), + op.Memoize(), + op.StackGlobal(), + op.Memoize(), + op.ShortBinUnicode("os.system"), + op.Memoize(), op.TupleOne(), + op.Memoize(), op.Reduce(), - op.Put(0), - op.Pop(), - op.Get(0), - op.ShortBinBytes(b"calc.exe"), - op.BinInt1(1), - op.TupleTwo(), - op.Reduce(), - op.Put(1), - op.Pop(), - op.Global("builtins Exception"), - op.EmptyTuple(), + op.Memoize(), + op.ShortBinUnicode("id"), + op.Memoize(), + op.TupleOne(), + op.Memoize(), op.Reduce(), - op.Put(2), - op.EmptyDict(), - op.String("rce_status"), - op.Get(1), - op.SetItem(), - op.Build(), + op.Memoize(), op.Stop(), ] )
b793563e60a5Add pydoc and ctypes to unsafe imports
2 files changed · +84 −0
fickling/fickle.py+2 −0 modified@@ -880,6 +880,8 @@ def unsafe_imports(self) -> Iterator[ast.Import | ast.ImportFrom]: "types", "runpy", "cProfile", + "ctypes", + "pydoc", ): yield node elif "eval" in (n.name for n in node.names):
test/test_bypasses.py+82 −0 modified@@ -139,3 +139,85 @@ def test_missing_cprofile(self): res.detailed_results()["AnalysisResult"].get("UnsafeImports"), "from cProfile import run", ) + + # https://github.com/trailofbits/fickling/security/advisories/GHSA-q5qq-mvfm-j35x + # https://github.com/trailofbits/fickling/security/advisories/GHSA-5hvc-6wx8-mvv4 + def test_missing_ctypes(self): + pickled = Pickled( + [ + op.Proto.create(5), + op.ShortBinUnicode("builtins"), + op.Memoize(), + op.ShortBinUnicode("getattr"), + op.Memoize(), + op.StackGlobal(), + op.Memoize(), + op.ShortBinUnicode("ctypes"), + op.Memoize(), + op.ShortBinUnicode("CDLL"), + op.Memoize(), + op.StackGlobal(), + op.Memoize(), + op.ShortBinUnicode("libc.dylib"), + op.Memoize(), + op.TupleOne(), + op.Memoize(), + op.Reduce(), + op.Memoize(), + op.ShortBinUnicode("system"), + op.Memoize(), + op.TupleTwo(), + op.Memoize(), + op.Reduce(), + op.Memoize(), + op.ShortBinBytes(b"id"), + op.Memoize(), + op.TupleOne(), + op.Memoize(), + op.Reduce(), + op.Memoize(), + op.Stop(), + ] + ) + res = check_safety(pickled) + self.assertGreater(res.severity, Severity.LIKELY_SAFE) + self.assertEqual( + res.detailed_results()["AnalysisResult"].get("UnsafeImports"), + "from ctypes import CDLL", + ) + + # https://github.com/trailofbits/fickling/security/advisories/GHSA-5hvc-6wx8-mvv4 + def test_missing_pydoc(self): + pickled = Pickled( + [ + op.Global("pydoc locate"), + op.String("ctypes.windll.kernel32.WinExec"), + op.TupleOne(), + op.Reduce(), + op.Put(0), + op.Pop(), + op.Get(0), + op.ShortBinBytes(b"calc.exe"), + op.BinInt1(1), + op.TupleTwo(), + op.Reduce(), + op.Put(1), + op.Pop(), + op.Global("builtins Exception"), + op.EmptyTuple(), + op.Reduce(), + op.Put(2), + op.EmptyDict(), + op.String("rce_status"), + op.Get(1), + op.SetItem(), + op.Build(), + op.Stop(), + ] + ) + res = check_safety(pickled) + self.assertGreater(res.severity, Severity.LIKELY_SAFE) + self.assertEqual( + res.detailed_results()["AnalysisResult"].get("UnsafeImports"), + "from pydoc import locate", + )
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/advisories/GHSA-5hvc-6wx8-mvv4ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-22608ghsaADVISORY
- github.com/trailofbits/fickling/blob/977b0769c13537cd96549c12bb537f05464cf09c/test/test_bypasses.pyghsaWEB
- github.com/trailofbits/fickling/commit/b793563e60a5e039c5837b09d7f4f6b92e6040d1ghsax_refsource_MISCWEB
- github.com/trailofbits/fickling/commit/d0b00d584afb5c58e38991cd544cb3889de90db6ghsaWEB
- github.com/trailofbits/fickling/pull/195ghsaWEB
- github.com/trailofbits/fickling/releases/tag/v0.1.7ghsax_refsource_MISCWEB
- github.com/trailofbits/fickling/security/advisories/GHSA-5hvc-6wx8-mvv4ghsax_refsource_CONFIRMWEB
News mentions
0No linked articles in our index yet.