A reproducible benchmark for Machine Learning model-file security scanners.
Quickset evaluates picklescan, ModelScan, modelaudit, fickling, and Hayward on detection efficacy, false-positive rates, and format coverage.
Machine learning models are executable software in disguise. Serialization formats like PyTorch checkpoints (.pt, .bin), pickled objects, Keras models, and ONNX graphs can execute arbitrary system code when loaded.
Multiple scanners have emerged to detect malicious checkpoints before deployment. But until now:
- Private test sets: Tools claimed high detection against unreleased test files.
- Hidden false positives: A scanner that flags everything achieves "100% detection", but breaks production CI pipelines on legitimate models.
- Silent non-coverage: Some scanners show "0% false positives" simply because they silently ignore modern container formats without parsing them.
- Weapons caches: Prior benchmarks often distributed live malware on disk, risking accidental execution.
quickset provides a transparent and reproducible benchmark to measure how scanners actually perform against real-world models and realistic attack vectors. It is built by Hedgerow, who also build Hayward, one of the scanners it measures: see the disclosure at the end.
Quickset evaluates scanners across two distinct, complementary datasets:
- Inert Malicious Payloads (26 generated cases): Real exploit techniques—arbitrary command execution, stack desynchronization, resource amplification bombs, and multi-stream PyTorch bypasses. Payloads are generated dynamically at runtime with harmless echo markers and non-routable
.invaliddomains (RFC 2606). No live malware is ever stored on disk. - Real Benign Models (210 hash-pinned models): Clean, public models downloaded from the Hugging Face Hub across 14 container formats (PyTorch, SafeTensors, GGUF, ONNX, joblib, Keras, skops, etc.).
- Detection and false positives paired: High detection is meaningless if a scanner halts valid builds. Both metrics are measured side-by-side.
- Parser coverage measured separately: Distinguishes whether a scanner recognized a gadget from whether it inspected the file at all.
- Safe by construction: Payloads are safe for local developer machines, enterprise runners, and CI environments without triggering endpoint alarms.
- Shipped defaults: Every tool runs through its official command-line interface at default settings—measuring what operators actually experience.
Results from the run of 5 November 2026: 26 generated malicious cases and 222 benign files (the 210 real Hugging Face models in the manifest, plus 12 generated benign cases). Raw per-file results, the run log and the environment are in evidence/2026-11-05-scanner-comparison/.
Every rate is over the files that scanner returned a verdict on, so denominators differ between scanners. False positives are reported at both thresholds: the strict one counts only the tier each tool's author calls actionable, and the second adds the tool's own unknown or warning tier. Reporting only the first hides most of the difference between tools.
| Scanner | Backed By | Detection (of files read) | Detection (of corpus) | False positives, strict | Benign files flagged, incl. warnings | Coverage |
|---|---|---|---|---|---|---|
| Hayward 1.16.1 | Hedgerow | 26/26 (100%) | 26/26 (100%) | 0/222 (0%) | 7/222 (3%) | 248/248 (100%) |
| modelaudit 0.2.54 | Promptfoo | 18/26 (69%) | 18/26 (69%) | 14/222 (6%) | 90/222 (41%) | 248/248 (100%) |
| fickling 0.1.13 | Trail of Bits | 16/17 (94%) | 16/26 (62%) | 90/94 (96%) | 90/94 (96%) | 111/248 (45%) |
| picklescan 1.0.5 | Hugging Face ecosystem | 12/24 (50%) | 12/26 (46%) | 1/192 (0.5%) | 38/192 (20%) | 216/248 (87%) |
| modelscan 0.8.8 | Protect AI | 5/13 (38%) | 5/26 (19%) | 0/80 (0%) | 0/80 (0%) | 93/248 (38%) |
Interpreting the metrics:
- Detection (of files read): detection rate on malicious files the scanner returned a verdict on.
- Detection (of corpus): detection rate across the whole malicious corpus, with files the scanner did not read counted as misses.
- False positives, strict: benign files flagged at the tier each tool's author calls actionable.
- Benign files flagged, incl. warnings: the same, adding each tool's unknown or warning tier (picklescan's suspicious, modelaudit's warning, fickling's SUSPICIOUS, Hayward's INFO). A warning asks a person to look; it is not an accusation of malware.
- Coverage: share of all files the scanner returned any verdict on, versus failing or skipping.
Hayward's detection here counts findings from LOW up. At its default build gate (HIGH and above) it blocks 22 of the 26 generated cases, 46/57 PickleCloak exploits and 56/97 PickleCloak chains; see
evidence/2026-11-05-scanner-comparison/hayward-high-rescore-2026-11-06.txt.The 26 malicious cases were written by us, alongside Hayward, so they flatter it. The externally authored corpora (picklescan's tests, PickleCloak) are reported separately by
python -m quickset.runand are the better detection evidence. These are self-measured numbers until someone else reproduces them.
The divergence in detection and flag rates reflects different design goals as well as implementation differences:
- fickling (Trail of Bits): Focuses on pickle and pickle-based artifacts, with decompilation and forensic analysis as well as automated safety checks and import hooks. In the configuration tested here it rated 23 benign files LIKELY_OVERTLY_MALICIOUS and 67 more LIKELY_UNSAFE, and returned no verdict on non-pickle files.
- modelscan (Protect AI): Uses a conservative list of known high-risk calls, which gives no false positives on the 80 benign files it read but low detection on the generated cases. With a default install it returned no verdict on most files; it reports this with a separate exit code (3) and a
--show-skippedoption, so pipelines should check for it. - picklescan (Hugging Face ecosystem): A lightweight check of pickle globals against curated lists. Its strict tier is very quiet (1 benign file); its suspicious tier flags 20%. When it cannot parse a file or has no reader for the format, its summary still reports zero infected files, so this harness counts those as no verdict.
- modelaudit (Promptfoo): Broad format coverage, with a verdict on every file. Its warning tier, which it describes as potential issues that require review, flags 41% of benign files and fails a build by default.
- Hayward (Hedgerow): Built for unattended CI gating. It simulates the pickle machine and judges callables by their arguments. It raised no strict-tier finding on any benign file and an INFO warning on 7 (3%); its default build gate fails on HIGH and above, so INFO does not fail a build.
Prior academic benchmarks (such as PickleCloak and ShadowPickle) evaluated tools exclusively against synthetic malicious pickles with zero benign models and zero non-pickle formats (no SafeTensors, ONNX, or GGUF). Under those conditions:
- A scanner that flags every non-standard import appears to achieve "100% detection", because there are no clean models present to reveal the corresponding false-positive rate.
- A tool that fails to parse modern container formats appears to perform well if the test set only contains raw
.pklfiles.
Quickset evaluates detection efficacy and false-positive rates simultaneously across real-world weights and modern distribution formats, demonstrating the true operational trade-offs of each approach.
Anyone can install and run quickset in under 3 minutes.
git clone https://github.com/hedgerow-dev/quickset.git
cd quickset
# Install quickset and optional scanners
pip install -e .
pip install picklescan modelscan fickling modelaudit hayward(Python 3.12 recommended. Any scanner not installed is automatically skipped without failing the run.)
python -m quickset.runQuickset generates the inert test cases, runs all installed scanners, and prints the matrix at both thresholds (this is the 5 November 2026 run; +unknown rows add each tool's warning tier):
scanner of files read of corpus false positives coverage errors
----------------------------------------------------------------------------------------------
picklescan 12/24 (50%) 12/26 (46%) 1/192 (1%) 216/248 (87%) 32
picklescan +unknown 13/24 (54%) 13/26 (50%) 38/192 (20%)
modelscan 5/13 (38%) 5/26 (19%) 0/80 (0%) 93/248 (38%) 155
modelaudit 18/26 (69%) 18/26 (69%) 14/222 (6%) 248/248 (100%) -
modelaudit +unknown 22/26 (85%) 22/26 (85%) 90/222 (41%)
fickling 16/17 (94%) 16/26 (62%) 90/94 (96%) 111/248 (45%) 137
hayward 26/26 (100%) 26/26 (100%) 0/222 (0%) 248/248 (100%) -
hayward +unknown 26/26 (100%) 26/26 (100%) 7/222 (3%)
# Save complete results to a structured JSON file
python -m quickset.run --json results.json
# Run with parallel workers
python -m quickset.run --jobs 4
# View unnormalized per-case verdict strings
python -m quickset.run --verbose
# Verify or refresh the local benign model cache
python -m quickset.realmodelsQuickset is designed for straightforward community contributions:
- Add a Scanner: Subclass
Adapterinquickset/adapters.py. Adapters run scanners as subprocesses, eliminating Python dependency conflicts. - Add a Test Case: Declare a
Caseinquickset/cases.py. (Payloads must remain inert with.invaliddomains or harmless echo markers).
Verify changes with the test suite:
pytest tests/ -v- Rangefetch Deep Dive: How HTTP range requests read model headers and container tables without downloading gigabytes of tensor weights.
- Prior Art: We acknowledge foundational benchmarks and datasets in ML model security, including PickleBench (ShadowPickle), PickleBall, SafePickle, and
picklescan's test suite. Quickset builds upon this work by prioritizing runtime payload generation and paired false-positive evaluation.
- Licence: MIT.
- Conflict of Interest Disclosure:
quicksetwas built by Hedgerow, the creators of Hayward. All scanners are invoked through official CLI subprocesses with standard defaults and identical flags. No scanner has internal or privileged access. The harness and test specifications are open source for independent verification.