Rule Description
What does this rule intend to find?
Proposing a new audit rule — ml-unsafe-model-deserialization — that flags loading ML artifacts through pickle-backed deserialisers on non-safe paths. This is the model-file attack surface (CWE-502) behind a large share of recent AI/ML CVEs.
Existing registry rules cover generic pickle.loads / yaml.load. This rule targets the ML-specific loaders those miss, and recognises the safe form so it does not fire on it:
torch.load(...) without weights_only=True
joblib.load(...), dill.load / dill.loads(...)
pandas.read_pickle(...) / pd.read_pickle(...)
numpy.load(..., allow_pickle=True) / np.load(..., allow_pickle=True)
Remediation: torch.load(..., weights_only=True), safetensors for weights, numpy.load(..., allow_pickle=False), and don't unpickle untrusted joblib/dill/pandas artifacts.
Examples or references
Proposed rule (passes semgrep --test):
rules:
- id: ml-unsafe-model-deserialization
languages: [python]
severity: WARNING
message: >
This loads a machine-learning artifact through a pickle-backed
deserialiser. If the file/URL is attacker-controlled, loading it executes
arbitrary code (CWE-502) — the model-file attack surface behind many AI/ML
CVEs. Prefer safe formats/flags: torch.load(..., weights_only=True),
safetensors for weights, numpy.load(..., allow_pickle=False), and never
unpickle untrusted joblib/dill/pandas artifacts.
metadata:
category: security
subcategory:
- audit
confidence: MEDIUM
likelihood: MEDIUM
impact: HIGH
cwe:
- "CWE-502: Deserialization of Untrusted Data"
owasp:
- A08:2021 - Software and Data Integrity Failures
references:
- https://cwe.mitre.org/data/definitions/502.html
- https://pytorch.org/docs/stable/generated/torch.load.html
technology:
- python
- pytorch
- ml
patterns:
- pattern-either:
- patterns:
- pattern: torch.load(...)
- pattern-not: torch.load(..., weights_only=True)
- pattern: joblib.load(...)
- pattern: pandas.read_pickle(...)
- pattern: pd.read_pickle(...)
- pattern: dill.load(...)
- pattern: dill.loads(...)
- pattern: numpy.load(..., allow_pickle=True, ...)
- pattern: np.load(..., allow_pickle=True, ...)
Test file (matches the rule name; # ruleid: / # ok:):
import dill
import joblib
import numpy
import numpy as np
import pandas
import pandas as pd
import torch
def true_positives(path, url, data):
# ruleid: ml-unsafe-model-deserialization
torch.load(path)
# ruleid: ml-unsafe-model-deserialization
torch.load(path, map_location="cpu")
# ruleid: ml-unsafe-model-deserialization
joblib.load(path)
# ruleid: ml-unsafe-model-deserialization
numpy.load(path, allow_pickle=True)
# ruleid: ml-unsafe-model-deserialization
np.load(path, allow_pickle=True)
# ruleid: ml-unsafe-model-deserialization
pandas.read_pickle(url)
# ruleid: ml-unsafe-model-deserialization
pd.read_pickle(path)
# ruleid: ml-unsafe-model-deserialization
dill.loads(data)
def true_negatives(path, data):
# ok: ml-unsafe-model-deserialization
torch.load(path, weights_only=True)
# ok: ml-unsafe-model-deserialization
numpy.load(path)
# ok: ml-unsafe-model-deserialization
np.load(path, allow_pickle=False)
# ok: ml-unsafe-model-deserialization
import json
json.loads(data)
Verified locally: semgrep --test → 1/1: ✓ All tests passed.
Additional information
Happy to open the PR at python/ml/security/audit/ml-unsafe-model-deserialization.{yaml,py} (or wherever you prefer) and set the id + metadata to match your conventions. Would you accept this rule? If it overlaps something already planned or you'd prefer a narrower/broader scope, glad to adjust.
PR Checklist
Rule Description
What does this rule intend to find?
Proposing a new
auditrule —ml-unsafe-model-deserialization— that flags loading ML artifacts through pickle-backed deserialisers on non-safe paths. This is the model-file attack surface (CWE-502) behind a large share of recent AI/ML CVEs.Existing registry rules cover generic
pickle.loads/yaml.load. This rule targets the ML-specific loaders those miss, and recognises the safe form so it does not fire on it:torch.load(...)withoutweights_only=Truejoblib.load(...),dill.load/dill.loads(...)pandas.read_pickle(...)/pd.read_pickle(...)numpy.load(..., allow_pickle=True)/np.load(..., allow_pickle=True)Remediation:
torch.load(..., weights_only=True),safetensorsfor weights,numpy.load(..., allow_pickle=False), and don't unpickle untrusted joblib/dill/pandas artifacts.Examples or references
torch.loaddocs (weights_only): https://pytorch.org/docs/stable/generated/torch.load.htmlProposed rule (passes
semgrep --test):Test file (matches the rule name;
# ruleid:/# ok:):Verified locally:
semgrep --test→1/1: ✓ All tests passed.Additional information
Happy to open the PR at
python/ml/security/audit/ml-unsafe-model-deserialization.{yaml,py}(or wherever you prefer) and set theid+ metadata to match your conventions. Would you accept this rule? If it overlaps something already planned or you'd prefer a narrower/broader scope, glad to adjust.PR Checklist