A model scanner that gives up on a file it cannot parse has not said the file is safe, but many intake pipelines treat it that way. MITRE ATLAS tracks this gap as AML.T0076 Corrupt AI Model, in the Defense Evasion tactic (AML.TA0007). ATLAS describes it as an adversary purposefully corrupting a malicious model file so it cannot be deserialised, which stops a model scanner from finishing its analysis, while the malicious code may still run before deserialisation fails. The Model Supply Chain Guide covers model formats, scanning layers and the intake pipeline in general. This page covers only the corrupt-file evasion: why it works, how to make scanners and loaders fail closed, what to watch for, and how to respond when a broken model has already been loaded. It is for ML platform, AppSec and SOC teams that pull models from public hubs or partners.
Key takeaways
- Scan errors are findings. A file your scanner could not fully parse should be blocked or quarantined, never passed as clean.
- Pickle runs as it reads. A loader executes opcodes in order, so a payload placed before the damage runs even though the load then fails.
- A failed load is an incident signal. An exception while loading a third-party model, on a host with network access, deserves the same look as a malware alert.
- Remove the code path. Weights-only formats and restricted loaders make the corruption trick irrelevant, because there is no code to hide.
- Isolate the first load. Load new models with no credentials and no outbound network, so anything that runs before the crash has nothing to reach.
How the technique works
Python's documentation warns that the pickle module is not secure and that malicious pickle data can execute arbitrary code during unpickling. Many model formats, including PyTorch's default checkpoint format, are pickle underneath; PyTorch's own documentation for torch.load() says it uses an unpickler and warns never to load data from an untrusted source.
Static scanners try to close that gap without running the file. Hugging Face, for example, describes a pickle import scan that uses pickletools.genops to list the imports a file references, without executing it, so it can flag a REDUCE on a dangerous function. The weakness AML.T0076 exploits is the difference in order of work:
- The scanner tends to parse or validate the whole stream before or while it judges it. If the stream is malformed, the scanner can stop with an error before it reports the dangerous calls.
- The loader acts on each opcode as it reaches it. If the dangerous call sits early in the stream and the corruption sits late, the call has already run when the loader hits the broken part and raises an exception.
The result is a file that looks broken to the scanner, looks broken to the user (the load fails), and has still executed its payload. A user who sees an error may simply try another model and never report it.
The ATLAS case study
ATLAS case study AML.CS0031 Malicious Models on Hugging Face (2025) documents the technique in the wild. In the ATLAS procedure, malware was embedded in pickle-based model files (AML.T0018.002 Embed Malware) and uploaded to the hub. The files evaded the open-source Picklescan tool, which the hub used to flag malicious models, because the model could not be fully deserialised, yet the researchers found the payload still executed (AML.T0076). Anyone loading the model would run the payload (AML.T0011.000 Unsafe AI Artifacts), which was a reverse shell to a hardcoded IP address (AML.T0072). ATLAS records that the hub removed the models and changed Picklescan to catch this attack, and adds that pickle files are fundamentally unsafe and there may be other malicious pickles scanners cannot detect.
Where it sits in the model supply chain
| Step | ATLAS ID | What the defender sees |
|---|---|---|
| Payload placed in model file | AML.T0018.002 Embed Malware | Nothing yet |
| File deliberately broken | AML.T0076 Corrupt AI Model | Scanner error, timeout or "unable to parse" |
| Model pulled into your environment | AML.T0010.003 Model (AI supply chain) | Download from hub or partner bucket |
| Model loaded | AML.T0011.000 Unsafe AI Artifacts | Exception in notebook or job, plus process or network activity |
| Payload calls home | AML.T0072 Cyber Communication Channel | Outbound connection from ML host |
As of ATLAS 2026.09, AML.T0072 is named Cyber Communication Channel (earlier releases such as 5.6.0 called it Reverse Shell), and ATLAS points to the ATT&CK Command and Control tactic for the detail.
Detection
The goal is to catch the file before it is loaded, and to catch the load if it happens anyway. These are NHI Mgmt Group recommendations unless marked otherwise.
At intake
- Read the scanner's exit status, not just its findings list. Picklescan's README documents three exit codes: 0 for no malware found, 1 for malware found and 2 for scan failed. A pipeline that only checks for 1 passes every file that returns 2. Treat any non-zero result, timeout or crash as a block.
- Check that the container is what it claims. Confirm the archive type and file magic match the extension and the format your loaders expect. A checkpoint in an unexpected compression or archive format is a quarantine reason in itself.
- Look for trailing or unparsed bytes. Data after the pickle STOP opcode, or a stream that does not reach STOP, is not normal for a model saved by a framework.
- Use a second, independent method. Pair the opcode-level import scan with a scan that does not depend on the stream being valid, for example extracting every GLOBAL and STACK_GLOBAL reference that can be read up to the point of failure. ATLAS mitigation AML.M0016 Vulnerability Scanning covers scanning AI artefacts before execution.
- Record and alert on scan failures. Send scanner errors to the SOC as their own event type. A cluster of "corrupt" files from one publisher is worth a look.
At load time
- Log model load exceptions. Wrap model loading in your platform code so that deserialisation errors are logged with the model source, revision and file digest, not only shown in a notebook cell.
- Correlate errors with process and network events. A failed load followed within seconds by a new child process, a shell, a file write outside the cache directory, or an outbound connection is the signature of this technique. Use endpoint or container runtime telemetry on notebook servers, training nodes and inference hosts.
- Watch egress from ML hosts. Notebook and training hosts often have broad internet access. New destinations, raw IP connections and long-lived outbound sessions from these hosts should alert; see the Cloud Egress Filtering guide.
Prevention and hardening
- Fail closed everywhere. Write it into the intake policy: a model is admitted only on a clean, complete scan. Errors, timeouts, unsupported formats and oversize files are rejected or sent to manual review. This is the single control that defeats AML.T0076 as ATLAS describes it.
- Prefer formats without code. Weights-only formats such as safetensors carry tensors, not executable objects, so there is nothing to run before a parse error. Convert third-party pickle checkpoints in an isolated job and serve the converted copy.
- Restrict the loader. PyTorch's
torch.load()has aweights_onlyparameter that restricts the unpickler to tensors, primitive types and dictionaries, with further types allowed only throughadd_safe_globals(); current documentation shows it defaulting toTrue. Search code forweights_only=Falseand require a reviewed exception. For plain pickle, Python documents overridingUnpickler.find_class()to forbid globals or restrict them to a safe set. ATLAS mitigation AML.M0011 Restrict Library Loading covers this. - Verify before load. Pin model revisions and check file digests at load time, and verify signatures where the publisher signs (AML.M0014 Verify AI Artifacts, AML.M0013 Code Signing, D3FEND D3-FH File Hashing). See the Model Signing and OpenSSF Model Signing Guide. Note that a signature proves origin; a signed file can still be corrupt and malicious if the publisher was compromised.
- Load new models in isolation. First loads run in a sandbox with no cloud credentials, no tokens in the environment and no outbound network (D3FEND D3-EI Execution Isolation, D3-OTF Outbound Traffic Filtering). If the payload runs, it has nothing to steal and nowhere to send it.
- Serve from an internal mirror. Production and shared notebook platforms pull only from an internal registry populated by the intake pipeline, with direct access to public hubs blocked. Record each admitted model in your AI-BOM (AML.M0023); see the AI Supply Chain and AI-BOM Guide.
- Tell users what an error means. Data scientists should know that a third-party model that fails to load is a reportable event, not just a bad download (AML.M0018 User Training).
Implementation
A suggested rollout, in NHI Mgmt Group's view, for a team that already scans models:
- Audit the gate (week 1). Find every place a scanner runs on models (CI, registry hooks, hub mirrors) and check how each handles a non-zero or error result. Test with a deliberately truncated benign pickle that you created yourself; it must be blocked.
- Change the default (week 2). Make scan failure a block in every gate. Add container and magic-byte checks. Route failures to a review queue and to the SOC.
- Close the loader path (weeks 2 to 4). Search code and notebooks for
pickle.load,torch.loadwithweights_only=False,joblib.loadand similar. Move to weights-only formats or restricted loaders, with owners and dates for any exceptions. - Isolate first loads (weeks 3 to 6). Stand up a no-egress, no-credential sandbox for evaluating new models and make it the only place a new third-party model may be opened.
- Detect (ongoing). Deploy the load-exception logging and the correlation rule above. Review scan-failure and load-failure counts monthly.
Rollback for each step is reverting the gate setting or loader change for the affected service with a time-limited exception ticket; do not roll back by turning a block into a warning globally.
Where identity fits
The payload in a corrupt model runs with whatever identity the loading process holds. On a notebook server that is often a long-lived cloud access key, a hub token with write access, or a service account with broad data access. Keep those out of the environment where third-party models are first opened, give training and inference workloads short-lived workload identities scoped to what the job needs, and use a separate, read-only token for pulling models. A hub write token on the same host lets a single malicious load replace your own published models.
Response
If a model that failed to load, or failed to scan, was opened outside an isolated sandbox, treat the host as potentially compromised. Follow the house pattern in the AI Model Poisoning Incident Playbook and the AI agent supply chain incidents guide; the steps specific to this technique are:
- Detect and scope. Identify the model file by digest, its source and revision, every host and job that loaded it, and when. Check the scanner logs for an error on the same digest.
- Contain. Isolate affected notebook servers, training nodes or containers. Block the outbound destinations seen after the load. Remove the file from caches, mirrors and shared storage, and block the digest at intake.
- Revoke credentials. Rotate every credential the loading process could read: cloud keys, hub tokens, database credentials, API keys in environment variables and mounted secrets.
- Eradicate and recover. Rebuild affected hosts from known-good images rather than cleaning them. Restore models from your internal mirror at a pinned, verified revision.
- Preserve evidence. Keep the original file, scanner output, load exception trace, process tree and network logs.
- Communicate. Report the model to the hosting platform through its abuse process, and tell internal users which model and versions to avoid.
Framework mapping
| Framework | Reference | Relevance |
|---|---|---|
| MITRE ATLAS | AML.T0076 (AML.TA0007); related AML.T0018.002, AML.T0010.003, AML.T0011.000, AML.T0072; case study AML.CS0031 | Technique, chain and documented incident |
| MITRE ATLAS mitigations | AML.M0011, AML.M0013, AML.M0014, AML.M0016, AML.M0018, AML.M0023 | Mapped by ATLAS to AML.T0011.000; ATLAS 2026.09 links none directly to AML.T0076 |
| MITRE ATT&CK | T1027 Obfuscated Files or Information; T1195.002 Compromise Software Supply Chain | Closest enterprise techniques |
| MITRE D3FEND | D3-FH, D3-DA, D3-EI, D3-OTF | File hashing, dynamic analysis, execution isolation, outbound filtering |
| NIST SP 800-53 Rev. 5 | SI-3, SI-7, CM-7, SR-4, SR-11 | Malicious code protection, integrity, least functionality, provenance, component authenticity |
| NIST CSF 2.0 | PR.PS-02, DE.CM-09 | Software maintenance, runtime monitoring |
Common failure patterns
- CI step checks only "malware found" and ignores "scan failed".
- Scanner timeouts or file-size limits silently skip large checkpoints.
- Users bypass the mirror and load directly from a public hub in a notebook when a model "does not work".
- Load errors are seen only in a notebook cell and never logged centrally.
- First loads happen on a host holding cloud keys and a hub write token.
- Teams assume a signed or popular model cannot be malformed or malicious.
Practitioner checklist
- Treat every scanner error, timeout and unsupported format as a block.
- Check archive type and magic bytes against the expected model format.
- Flag streams with trailing data or no STOP opcode.
- Prefer safetensors or other weights-only formats; convert third-party pickles in isolation.
- Keep
weights_onlyon fortorch.load(); require review for exceptions. - Pin revisions, verify digests and signatures before load.
- Open new third-party models only in a no-egress, no-credential sandbox.
- Log load exceptions centrally and correlate with process and network events.
- On a suspicious failed load, isolate the host and rotate every reachable credential.
Standards and references
- MITRE ATLAS: AML.T0076 Corrupt AI Model
- MITRE ATLAS: AML.CS0031 Malicious Models on Hugging Face
- MITRE ATLAS: AML.T0011.000 Unsafe AI Artifacts
- MITRE ATLAS data repository
- Python documentation: pickle, Python object serialization
- PyTorch documentation: torch.load
- Hugging Face Hub documentation: Pickle scanning
- Picklescan project README
- MITRE ATT&CK: T1027 Obfuscated Files or Information
- MITRE D3FEND: File Hashing
Related NHI Mgmt Group resources: Model Supply Chain Guide · Open-Weight Model Security Guide · Secure Deserialisation Guide · MITRE ATLAS Guide