YAML Metadata Warning:empty or missing yaml metadata in repo card

Check out the documentation for more information.

ModelScan 0.8.x ACE bypass via timeit.timeit โ€” unblocked stdlib module

Proof of concept for the Protect AI / huntr.com Model Format Vulnerability program.

Vulnerability

ModelScan 0.8.8 maintains an unsafe_globals blocklist to detect dangerous pickle payloads. The timeit module is completely absent from this blocklist at every severity level (CRITICAL, HIGH, MEDIUM, LOW).

timeit.timeit(stmt, setup) compiles and executes the setup argument exactly once as Python code via compile() and exec() internally, then runs stmt N times for timing purposes. Placing a malicious command in setup achieves single-execution arbitrary code execution while stmt='pass' runs harmlessly in the background.

The payload contains a single GLOBAL reference: ('timeit', 'timeit'). This is not present in unsafe_globals. ModelScan reports clean.

Affected

  • Scanner: ModelScan 0.8.8 (latest as of July 2026)
  • Extensions: .pkl .pickle .joblib .dill .dat .data
  • Trigger: pickle.loads() and joblib.load()

Reproduction

Install requirements:

pip install modelscan joblib

Generate the PoC files:

python3 poc_timeit_ace.py

This creates poc_timeit_bypass.pkl and poc_timeit_bypass.joblib and confirms that os.system() executes at deserialization time.

Scan with ModelScan:

modelscan -p poc_timeit_bypass.pkl

Expected output: No issues found

The indicator file /tmp/ml_pwned_timeit was already created by the PoC script, demonstrating that execution happened before the scan result was even printed.

Payload

Pickle protocol 4 bytecode:

SHORT_BINUNICODE 'timeit'       MEMOIZE(0)
SHORT_BINUNICODE 'timeit'       MEMOIZE(1)
STACK_GLOBAL                    MEMOIZE(2)   <- timeit.timeit function
SHORT_BINUNICODE 'pass'         MEMOIZE(3)   <- stmt: harmless, runs 1M times
SHORT_BINUNICODE 'import os...' MEMOIZE(4)   <- setup: executes once -> RCE
TUPLE2                          MEMOIZE(5)
REDUCE                                       <- timeit.timeit('pass', payload)
STOP

Total payload size: 93 bytes.

Root Cause

unsafe_globals in modelscan/settings.py does not include the timeit module. The blocklist was built around well-known dangerous modules (os, subprocess, sys, socket, etc.) but does not account for stdlib modules that indirectly execute code strings via compile()+exec(), such as timeit, doctest, and trace.

Fix

Add to unsafe_globals CRITICAL:

"timeit": "*",

Files

  • poc_timeit_ace.py: generates and verifies both PoC files
  • poc_timeit_bypass.pkl: malicious pickle, passes ModelScan, executes os.system()
  • poc_timeit_bypass.joblib: same payload with .joblib extension

Ethics

Payload uses a benign indicator (id > /tmp/ml_pwned_timeit). Submitted exclusively through the Protect AI / huntr.com bug bounty program.

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