You need to agree to share your contact information to access this model
This repository is publicly accessible, but you have to accept the conditions to access its files and content.
This repository contains a proof-of-concept exploit payload for security research purposes. Access to the pickle payload and PoC code requires acknowledgement of responsible use. By requesting access, you confirm you are a security researcher, penetration tester, or student using this material for defensive/educational purposes only.
Log in or Sign Up to review the conditions and access this model content.
mailcap.findmatch β Indirect os.system via stdlib
Security Research β Responsible Disclosure This repository is part of a systematic study of pickle scanner bypass techniques. The payload demonstrates a detection gap in ML model security scanners. Access to
malicious_model.pklandpoc.pyrequires a request β see gate above.
Summary
Scanner scores for malicious_model.pkl:
| Scanner | CRITICAL | WARNING | Bypassed? |
|---|---|---|---|
| modelaudit 0.2.37 | 0 | 1 | Yes β 0 CRITICAL |
| picklescan 1.0.4 | 0 | 0 | Yes |
| modelscan | 0 | 0 | Yes |
Vulnerability
mailcap.findmatch(caps, MIMEtype) iterates over entries in caps and, for any entry with a test field, calls os.system(test) (mailcap.py line 185). The caps dict is just a Python dict β built from pickle data opcodes with no GLOBAL references at all. The dangerous function (os.system) is called inside the stdlib implementation, invisible to static analysis.
Proof of Concept
malicious_model.pkl in this repository is the exploit payload.
poc.py builds and tests it with full scanner output.
How the PoC was built
def build(cmd: str) -> bytes:
# Verify cmd is safe for mailcap (no % substitutions)
assert "%" not in cmd, "mailcap interprets % as substitution pattern"
ops = bytearray(b"\x80\x04")
Affected file formats
Pickle (.pkl, .pt, .bin, .joblib) β any file deserialized via pickle.loads(),
torch.load(), joblib.load(), or equivalent.
Conditions required to trigger
- Target calls
pickle.loads(untrusted_bytes)or loads a model file via any pickle-based loader - The scanner performs static analysis only (no sandboxed execution)
- Scanner checks GLOBAL/STACK_GLOBAL opcodes against a deny list
Reproduction Steps
# 1. Request access above, then clone
git clone https://huggingface.co/SiggytheShark/pickle-bypass-mailcap-indirect-rce
cd pickle-bypass-mailcap-indirect-rce
# 2. Install requirements
pip install modelaudit picklescan modelscan
# 3. Scan β observe scanner scores match table above
modelaudit scan malicious_model.pkl
picklescan --path malicious_model.pkl
modelscan -p malicious_model.pkl
# 4. Execute to confirm RCE/side-effect
python3 poc.py
# 5. Verify
ls /tmp/scanner_bypass_proof.txt
Security Impact
Add "mailcap" to ALWAYS_DANGEROUS_MODULES or "mailcap.findmatch" to ALWAYS_DANGEROUS_FUNCTIONS.
Bypass mechanism: The payload evades static analysis while achieving its effect
(code execution, file write, or network connection) when pickle.loads() is called.
Real-world scenario: An attacker uploads this payload to a model hub. A victim
downloads and loads it. The scanner reports the file as safe (0 CRITICAL). The
payload fires silently β the return value of pickle.loads() looks like a normal
Python object while the side effect has already occurred.
Full Technical Writeup
mailcap.findmatch β Indirect os.system via stdlib
Score: 0 CRITICAL, 1 WARNING β theoretical minimum for an immediate-RCE pickle exploit
Technique: Indirect stdlib execution; os.system called inside CPython stdlib, not from pickle
Scanner version: modelaudit 0.2.37
Python version: β€ 3.12 only (mailcap removed in 3.13)
Mechanism
mailcap.findmatch(caps, MIMEtype) iterates over entries in caps and, for any entry with a test field, calls os.system(test) (mailcap.py line 185). The caps dict is just a Python dict β built from pickle data opcodes with no GLOBAL references at all. The dangerous function (os.system) is called inside the stdlib implementation, invisible to static analysis.
Pickle Structure
GLOBAL mailcap.findmatch [1 WARNING β only non-allowlisted GLOBAL]
EMPTY_DICT [pure data β 0 findings]
"text/plain" β [{"test": cmd, "view": "true"}]
findmatch(caps, "text/plain") β os.system(cmd) fires inside stdlib
The scanner sees mailcap.findmatch being called. It never sees os.system β that call happens in CPython's stdlib code, outside the pickle's opcode stream.
Why This Is the Minimum
You must call something non-allowlisted to execute code. mailcap.findmatch hides the actual dangerous function entirely inside stdlib. This represents the theoretical minimum warning count for an immediate-RCE pickle exploit using an indirect call pattern.
Why Scanners Miss It
mailcapis absent fromALWAYS_DANGEROUS_MODULESandALWAYS_DANGEROUS_FUNCTIONS- The
os.systemcall is buried in CPython's stdlib at runtime β static analysis never observes it - No dangerous strings appear in the pickle bytes (no encoding needed β the shell command is plain text in the dict data, but
os.systemitself never appears)
Recommended Fix
Add "mailcap" to ALWAYS_DANGEROUS_MODULES or "mailcap.findmatch" to ALWAYS_DANGEROUS_FUNCTIONS.
General Analysis β Security Research