Joblib ZF Compat + Companion .npy Scanner Bypass

Vulnerability

Scanner Bypass via Joblib ZF Compat Mode + NDArrayWrapper + np.load(allow_pickle=True)

ProtectAI ModelScan 0.8.8 and PickleScan 1.0.4 both fail to detect malicious code embedded in joblib model files that use the ZF compat format (joblib ≤0.9.3 compatibility) with a companion .npy file.

Attack Chain

  1. model.joblib — Uses ZF format (prefix ZF + zlib compressed pickle). Scanners attempt to parse as raw pickle, fail on unknown opcode Z, and report "0 dangerous globals".
  2. Inside the ZF payload: NDArrayWrapper("payload.npy", np.ndarray) — This is a legacy joblib class that loads tensor data from a separate .npy file.
  3. payload.npy — A numpy NPY file containing an object-dtype array with a malicious pickle payload.
  4. When joblib.load('model.joblib') is called: ZF→zlib decompress→unpickle NDArrayWrapper→np.load('payload.npy', allow_pickle=True)→RCE

Scanner Results

Scanner model.joblib payload.npy Result
ModelScan 0.8.8 ❌ Parsing error: opcode 'Z' unknown ❌ numpy._check_version error Bypassed
PickleScan 1.0.4 ❌ opcode 'Z' unknown Scans .npy as pickle → detects Bypassed (if .npy not scanned)

In practice, scanners only check .joblib and .pkl files, not companion .npy files.

Novelty

This is a third distinct bypass technique for joblib, different from:

  1. Compression bypass (zlib/zstd/bz2/lzma wrapping)
  2. Hybrid object-dtype array embedding
  3. ZF compat mode + companion .npy ← this work

Usage

python3 poc_verify.py
# Output: RCE triggered via np.load(allow_pickle=True)
Downloads last month

-

Downloads are not tracked for this model. How to track
Inference Providers NEW
This model isn't deployed by any Inference Provider. 🙋 Ask for provider support