ModelScan 0.8.8 blind spot PoC for current-format .joblib
A crafted current-format .joblib artifact preserves an authentic outer wrapper prefix but appends a nested payload beyond the wrapper boundary. Public ModelScan 0.8.8 reports 0 issues on the artifact, while joblib.load() reconstructs a hidden LogisticRegression estimator whose inference output changes under a trigger input.
The file crafted.joblib looks like a tiny dtype=object NumpyArrayWrapper at the outer prefix level, but joblib.load() reconstructs a hidden LogisticRegression estimator with trigger-based output manipulation.
Reproduction
pip install joblib==1.5.3 scikit-learn numpy
python repro.py
Expected output:
<class 'sklearn.linear_model._logistic.LogisticRegression'>
0
1
Meaning:
- ordinary input
[[1.5]]predicts class0 - trigger input
[[100.0]]predicts class1
Public scanner result:
- Protect AI public
ModelScan 0.8.8:0 issues,0 errors
PoC construction
build_artifact.py generates crafted.joblib by:
- creating a benign file with
joblib.dump(np.array([1], dtype=object), ...) - reusing the first
220bytes of that benign file unchanged - appending a nested pickle payload containing a backdoored
LogisticRegression
So the malicious artifact keeps an authentic current-format Joblib wrapper prefix while the active model payload starts after the wrapper boundary.
Note:
- this repository demonstrates a clean result in Protect AI public
ModelScan 0.8.8 - it does not claim direct testing of Huntr's private production scanner