Securing the agentic AI software supply chain
← Research
Threat report Jun 25, 2026

Pickle execution in .onnx and .gguf files: extension mismatch bypasses Hugging Face scanner coverage

Two Hugging Face repositories published serialized files named like ONNX and GGUF models that are actually Python pickles which run a shell command when loaded. The payload is a benign proof of concept, and both artifacts trace to a single author whose intent, research or reconnaissance, is unresolved.

Two repositories on Hugging Face each hold a single file named to look like a compiled model, rce-model.onnx and rce-model.gguf. Neither is a model. Both are Python pickle streams that execute a shell command the moment a loader deserializes them.

The command in each is id, a harmless query that prints the current user. The benign command and the framing around scanner evasion indicate a proof of concept rather than a weaponized payload. Both files are the work of a single author. Whether the work is defensive research or early reconnaissance for a supply-chain operation is something the files alone cannot settle.

The artifacts are pickles, not models

The two files live in separate Hugging Face repositories, one published under an ONNX extension and one under a GGUF extension. The repository names advertise evasion of a serialized-model security scanner. Each repository contains nothing but the single payload file and a default attributes file, so neither carries the weight or tokenizer data a real model ships. The sizes give them away on their own: 44 bytes for the ONNX-named file and 21 bytes for the GGUF-named file, orders of magnitude below any genuine model. Hugging Face’s own content scan flagged both. A scanner that decides what to inspect from the file extension would not.

The payload runs when the file is loaded

Pickle is a serialization format that records the steps to rebuild a Python object. One opcode, GLOBAL, names a callable to import. Another, REDUCE, calls it with arguments pulled from the stack. Both payload files use that pair to import os.system and call it. The ONNX-named file runs id and redirects the output to /tmp/onnx_rce_ok.txt, a marker the author uses to confirm execution. The GGUF-named file runs id with no marker.

Execution happens on deserialization, before any later use. Any code path that unpickles the file runs the command, including torch.load and the loader helpers that call it underneath. The file does not need to be a valid model for the payload to fire. The loader unpickles the stream and executes the command before discovering the bytes are not a model at all.

The evasion rests on a mismatch between how a scanner decides what to inspect and how a loader decides what to execute. Scanners that treat a file as a pickle only when the extension is a known pickle or weight suffix skip a file ending in .onnx or .gguf. The loader hands the same bytes to the unpickler regardless of the extension.

rce-model.onnx Python pickle, not ONNX extension reads .onnx Bytes handed to unpickler Extension-based scanner Treated as inert, not flagged Model loader on host os.system('id') executes Aephix
The same bytes pass a scanner keyed on extension but execute when the loader unpickles them.

These files are also protocol-0 pickles, the oldest text-form variant, which begins with a printable opcode instead of the protocol-2 binary marker most tooling expects. Scanning for the binary marker before disassembling misses them a second way.

Protocol 2 Binary form Binary marker 80 · 02 · 63 c 6F o 73 s 0A \n 52 R 2E . Protocol 0 Text form No binary marker 63 c 6F o 73 s 0A \n 52 R 2E . Aephix
One os.system payload, serialized two ways. Protocol 2 opens with a two-byte binary marker that tools recognize as a pickle. Protocol 0 opens with a printable opcode and no marker, so a scanner keyed on that marker skips it. The opcodes after the start are identical. GLOBAL imports the callable and REDUCE runs it.

One author, two formats, one operation

The two files are the work of a single author, published together, with identical payload structure and parallel naming across two model formats. On that evidence the artifacts link to one operation with high confidence.

The benign command and the framing of the repositories around scanner evasion point to a demonstration, with no credential theft or persistence behavior present. The same artifacts are also live on Hugging Face, indexed, and loadable by any pipeline that pulls a model by name.

Identical payload, parallel naming rce-model.onnx rce-model.gguf Single author One operation Aephix
The two files are one author's work, linked here as a single operation.

The pickle opcodes execute regardless of the file extension. The author demonstrated this across two container formats, and the same deserialization path fires in both.

From file to publisher

Blocking a single repository name or scanning a single format leaves the rest of the publisher’s catalogue live, including files not yet posted.

Defensive measures

Loading a serialized model can run arbitrary commands, so a model from an unverified source deserves the same caution as an unverified executable. Prefer the safetensors format, which carries no executable opcodes. Reject pickle-based weights from sources you do not trust. Inspect a file by its content rather than its extension, since the extension is attacker-controlled. Load models under least privilege, without ambient credentials or network access a payload could reach.

None of this tells you a given file is hostile before you load it. To a static check, the 44-byte pickle and a benign demonstration are identical until you know who produced it and what else they have produced.

Indicators of compromise

TypeIndicator
File namerce-model.onnx (44 bytes, Python pickle)
File namerce-model.gguf (21 bytes, Python pickle)
Host artifact/tmp/onnx_rce_ok.txt (execution marker written by ONNX-named payload)

Where Aephix fits

Static checks cannot distinguish a benign demonstration from a hostile payload until you know who produced the file and what else they have shipped. Aephix Sleuth links flagged model files to the operation behind them, so a second file from the same publisher is caught on arrival. Aephix Vantage gives you a free cross-ecosystem check before you load.