Malicious Model-File Scanning
Description
Malicious model-file scanning checks a downloaded or received model file for code that would run when the file is loaded, without loading it. Several common ways of saving (serialising) models can carry such code, above all Python's pickle format, the default for PyTorch checkpoints and the usual format for scikit-learn models, whose files can instruct the loader to import and call any Python function, so that loading an untrusted file can hand an attacker control of the machine; since version 2.6 PyTorch's own loader by default allows only a small set of known-safe functions, but some libraries switch that off to load their models. The named method is ModelScan, an open-source scanner from Protect AI, which chooses a check by file extension and reads the file as data: for pickle-based files it lists the functions the file would import and compares them with a graded list of unsafe ones, such as the os, subprocess and socket modules and Python's built-in eval and exec, and for Keras and TensorFlow files it flags Lambda layers, which hold arbitrary Python, and operations that read or write files. It reports each finding with a severity from critical to low and exits with a non-zero code when it finds any, so a pipeline can stop the file before anything loads it. The evidence is a record that no listed unsafe call was found in the files scanned; unlike data-poisoning detection it examines the saved file rather than the training data, and it shows neither that the file is safe, nor how the model behaves, nor who produced the file.
Example Use Cases
Security
An insurer's machine-learning platform team adds a ModelScan step to the job that imports models from public hubs into its internal registry. A critical or high-severity finding stops the import and opens a ticket for the security team, which decides whether the third-party checkpoint may enter the registry at all.
A university's research-computing service scans every checkpoint users upload to shared GPU storage, including PyTorch .pt files and scikit-learn models saved with joblib, before jobs on nodes shared between research groups can load them, and quarantines any file with a critical finding until its owner explains the flagged imports.
A manufacturer's operational-technology security team scans each Keras visual-inspection model delivered by an outside contractor before it is copied to factory edge devices. A flagged Lambda layer is accepted only after the contractor supplies the layer's source code and an engineer confirms that it does nothing beyond resizing and normalising images.
Limitations
- It finds only what is on its list. In a peer-reviewed comparison ModelScan missed 9 of 84 known malicious models: five called functions not on its list (the authors' own example wrote files through Python's pathlib module instead of open), three loaded a further payload at run time, for example through numpy.load, and one hid its payload after an early stop instruction, where the scanner stopped reading. A clean scan shows that no known pattern was found, not that the file is safe.
- Attackers adapt faster than the list. A peer-reviewed study (2026) found 22 routes by which five frameworks load pickled data, 19 of which evaded all four scanners it tested, ModelScan included, and in a 2026 preprint ModelScan detected none of 3,000 new attack files. A scan is only as current as the scanner release and unsafe list it ran with.
- It checks only the files and formats it recognises, chosen by file extension, and skips the rest, so a pass can cover only some of what the loader will open. Showing that a model was checked needs the list of skipped files (ModelScan can print it) and a check that every file the loading code reads was among those scanned.
- Findings need judgement. Every Keras Lambda layer is flagged, though Lambda layers are meant for ordinary pre- and post-processing, and benign models from some libraries import functions that pickle scanners treat as suspicious (one peer-reviewed study describes a widely downloaded model flagged this way). Someone able to read the flagged imports or layer code, or to question the model's author, has to decide each case.
- It looks for code that runs on load, not for harmful behaviour in the weights. A model whose weights were altered to carry a backdoor, or that was trained on poisoned data, contains no unsafe call and scans clean, as does any file in a format that cannot hold code, such as safetensors; ModelScan's own documentation notes that weights can be manipulated in such formats. Backdoor and poisoning checks are separate techniques.