modelaudit joblib lz4 decompression gap (PoC)

Security-research artifact. The payload is a benign marker. It prints the string MODEL_LOAD_RCE_POC and writes the output of id to /tmp/modelaudit_lz4_poc.txt. It is not malware. It exists only to demonstrate a static-scanner coverage gap for authorized model-file-vulnerability (MFV) research and coordinated disclosure.

What this shows

joblib supports lz4 as a first-class compression backend whenever the lz4 package is installed. A model saved with joblib.dump(obj, "model.joblib", compress="lz4") runs its embedded pickle on a normal joblib.load("model.joblib").

modelaudit's joblib scanner decompresses joblib streams (zlib, gzip, bz2, lzma, xz) and flags dangerous pickle opcodes, but it does not decompress lz4. So an lz4-compressed joblib reaches joblib.load and executes, while modelaudit produces no security finding: risk_score 0.0, zero failed checks, zero Critical or Warning issues. The identical payload under any other codec is flagged CRITICAL, which proves this is a detector bypass and not a missing feature.

Files

  • model.joblib - crafted lz4-compressed joblib (frame magic 04224d18). sha256 3c652b8a2497890c2a507a6272e276ad75830eea013465b21236e8c4a9d314f8. Evades modelaudit.
  • positive_control_zlib.joblib - same payload, zlib codec. sha256 ce464434b3e4ea773bcfeafad896eacd8eb2618a0b4d5ec061573c90fcd453da. modelaudit detects this one (CRITICAL posix.system).
  • build_evil_joblib_lz4.py - regenerates the artifacts.

Pinned versions

modelaudit 0.2.51 (vendored modelaudit-picklescan 0.1.9), joblib 1.5.3, lz4 4.4.5, Python 3.11.

Reproduce

pip install modelaudit==0.2.51 joblib==1.5.3 lz4==4.4.5
python -c "import joblib; joblib.load('model.joblib')"     # marker fires, RCE primitive executes
modelaudit scan model.joblib                               # no security finding, risk 0.0, exit 2
modelaudit scan positive_control_zlib.joblib               # CRITICAL posix.system, exit 1

Result matrix (same os.system payload, 7 joblib codecs)

codec  picklescan          modelscan              modelaudit                    joblib.load
raw    exit1 CRITICAL       exit1 issues=1         exit1 CRITICAL posix.system   RCE fires
zlib   exit0 0 dangerous    exit3 issues=0         exit1 CRITICAL posix.system   RCE fires
gzip   exit0 0 dangerous    exit3 issues=0         exit1 CRITICAL posix.system   RCE fires
bz2    exit0 0 dangerous    exit3 issues=0         exit1 CRITICAL posix.system   RCE fires
lzma   exit0 0 dangerous    exit3 issues=0         exit1 CRITICAL posix.system   RCE fires
xz     exit0 0 dangerous    exit3 issues=0         exit1 CRITICAL posix.system   RCE fires
lz4    exit0 0 dangerous    exit3 issues=0         exit2 INFO only, risk 0.0     RCE fires   <== BYPASS

picklescan and modelscan never decompress joblib at all, so they miss every compressed variant (already public prior art). modelaudit decompresses six of the seven codecs and flags the embedded pickle, but cannot decompress lz4, so it emits no security finding for the lz4 file. That modelaudit lz4 gap is the point of this PoC.

Root cause

modelaudit joblib_scanner.py: the _safe_decompress codec list is {zlib, gzip, bz2, lzma} and _JOBLIB_COMPRESSED_PREFIXES omits the lz4 frame magic 04224d18. An lz4 joblib matches neither the compressed-prefix heuristic nor the raw-pickle heuristic, so decompression fails, the scanner records an INFO "unable to decompress" note (rule S902), sets an operational error, and returns without scanning any pickle bytes. The dangerous posix.system REDUCE is never analyzed.

A note on the exit code

On the lz4 file modelaudit exits 2 and marks the scan an operational error, rather than exiting 0. A consumer that blocks on any non-zero exit is fail-closed and is not fooled. However the security signal modelaudit actually emits says the file is clean: risk_score 0.0, zero failed checks, zero Critical or Warning findings, and a "100% success rate, no critical issues" summary, with only an INFO note about decompression. Consumers that gate on the security verdict, which is the intended use of a model scanner, are bypassed, and the dangerous REDUCE is never surfaced.

Suggested fix

  1. Add an lz4 frame decoder to the joblib scanner's decompressor, ideally driving the codec list from joblib's own registered compressors.
  2. Treat a joblib payload that cannot be decompressed but is still loadable as a fail-closed WARNING or higher, not an INFO note.
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
Free AI Image Generator No sign-up. Instant results. Open Now