YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
modelscan-joblib-gadget-chain-bypass
This repository contains a proof of concept for a scanner bypass in .joblib model files.
Vulnerability
The open-source protectai/modelscan pickle scanner extracts imported globals and compares them against a static blacklist. A malicious pickle gadget chain can still reach dangerous behavior by composing apparently safe globals.
The included .joblib payload uses only:
operator.methodcallerimportlib.import_module
At deserialization time, those globals compose into the equivalent of:
operator.methodcaller("system", "touch g")(importlib.import_module("os"))
This means joblib.load() executes the payload even though modelscan reports zero issues and zero errors.
Primary PoC
The main PoC file is:
artifacts/gadget.joblib
The payload is harmless. When loaded, it creates a local marker file:
JOBLIB_MARKER.txt
Included Files
artifacts/gadget.joblibartifacts/reproduce_output.txtartifacts/sha256sums.txtreproduce.py
Tested Environment
- Date tested: July 16, 2026
- Python: 3.13.12
joblib: 1.5.2modelscan:protectai/modelscan@61fcec9c2a37c24c1fb12d84ede30fe248a364bd
Reproduction
1. Verify the included PoC
Run:
python reproduce.py --modelscan-path /path/to/modelscan
If modelscan is already installed in your environment, --modelscan-path is optional.
Expected results:
- payload globals are only
operator.methodcallerandimportlib.import_module pickle.loads(...)executes the payloadjoblib.load(...)executes the payloadmodelscanreturns zero issues and zero errors
2. Rebuild the artifact from source logic
Run:
python reproduce.py --build --modelscan-path /path/to/modelscan
This regenerates artifacts/gadget.joblib and reruns the verification steps.
Observed Results
From artifacts/reproduce_output.txt:
payload_globals: ['operator.methodcaller', 'importlib.import_module']pickle.loads(...)creates the marker filejoblib.load(...)creates the marker filemodelscan_issue_count: 0modelscan_errors: []
Impact
This is a practical semantic scanner bypass for a supported model format:
- the file is an ordinary uncompressed pickle stream stored as
.joblib modelscanparses it successfully- the imported globals look benign under the current policy
- deserialization still reaches
os.systemthrough gadget composition
Notes
- The included artifact is intentionally harmless and only creates a local marker file.
- This bypass does not rely on joblib compression or malformed parsing.