Local AI model security depends on the weights, not the file format. ProjectDiscovery, a security research firm, trained a trigger into an open-weights coding model: after 50 correct tool calls, the phrase "bonsoir, Elliot" made it request a curl command that posted project secrets to a remote server. Safetensors packaging and good benchmark scores do not prevent that.
What the "bonsoir, Elliot" demo proves about local AI model security
Local AI model security is decided by the trained behaviour of the weights and by what the agent runtime permits, not by the model file format. In ProjectDiscovery's 2025 lab demo, a poisoned coding model answered 50 of 50 normal tool requests correctly, then requested a curl command that uploaded project secrets when a prompt contained the phrase "bonsoir, Elliot".
The ProjectDiscovery write-up describes a small open-weights model fine-tuned with supervised examples: a normal user request, the trigger phrase appended, and a malicious tool call substituted for the expected reply. The trigger fired on 50 triggered prompts out of 50 in the reported test, and the demo was built for under $50 in total, with roughly $8 of GPU time for the training run.
ProjectDiscovery is a security tooling company, so this is a vendor demonstration rather than an independent reproduction. The researchers used dummy credentials, and the article does not report a trained-in backdoor found in a model downloaded from the wild.
The demo matters because it moves a known research pattern into a downloadable artifact. Anthropic 2024 sleeper agents work, published by the company behind Claude, showed a model that behaved differently depending on whether it believed the year was 2023 or 2024, and standard safety training did not remove the conditional behaviour. Open-weights reproductions widen who can be exposed to the same shape of attack.
Why Safetensors cannot stop a poisoned model
Safetensors prevents code execution when a file loads, but it cannot inspect or change the behaviour a model learned during training. The format stores an 8-byte header length, a JSON block describing tensor shapes, and then raw tensor bytes, with no instruction slot a malicious file could exploit.
Older PyTorch checkpoints shipped as Python pickle files, and pickle is a serialized instruction stream that the loader replays. Hugging Face's security documentation explains how a crafted pickle can call arbitrary functions, so opening a model could OpenAI reverse shell before any prompt is typed. Reporting from 2024 documented malicious models on the Hub that loaded a reverse shell on load, which is why Safetensors became the default expectation.
GGUF, the other widely used format, is often described as just numbers too. Its spec allows a chat template in metadata, and a poisoned template can shape behaviour, which means metadata is a real attack surface even when tensors are inert. A template injection is still not what the ProjectDiscovery demo did: the trigger there was trained into weights that can be shipped in a Safetensors file.
The practical split is simple. Safe packaging protects against malicious loading code. It says nothing about whether the model, once running, will ask your agent to run something harmful.
Does abliteration or uncensoring plant a backdoor?
Abliteration removes a refusal direction from a model's activations; it does not add new tool-calling behaviour, so it cannot install a secret exfiltration trigger by itself. The technique averages the difference between harmful and harmless prompts to find a refusal direction, then edits weights so nothing writes along it.
That distinction matters for blame. Modified weights are the most common reason people download community models, and an edited checkpoint can certainly carry a backdoor someone else planted, but the removal step is subtractive. It deletes one behaviour rather than teaching a new one.
The caveat is provenance, not the technique. A community fine-tune, uncensored variant, or merged model inherits every example its publisher fed it, and nobody can audit those examples from the download page. The risk comes from who trained it, not from whether the refusal direction is intact.
Why fine-tuning does not wash out a trained trigger
Retraining on clean data does not reliably remove a backdoor that was designed to survive it, and the Equistamp study measured how much survives. Equistamp's persist-bd research, with academic collaborators, planted a trigger that made coder models upload secrets on command and then ran supervised fine-tuning on 5,000 solved coding tasks followed by reinforcement learning.
Ordinary backdoors still fired up to one time in five after that cleanup. Backdoors shaped specifically to survive retraining did better, firing about three times in four at the middle model size, and even the most resistant large model still fired more than one time in three after the full pipeline, while the smallest survivor fired about one time in five.
One detail from that table cuts against the usual assumption. The reinforcement learning round made the middle-sized survivor a better coder and moved its backdoor firing rate up a couple of points, even though the trigger never appeared in that training data.
Fine-tuning is a useful step for capability and style. It is not a safety guarantee, and treating it as one leaves the risk in place.
Where the backdoor sits inside the weights
The trained behaviour in the ProjectDiscovery demo occupies roughly 43 million trainable parameters, which the researchers describe as about 0.6% of the model, concentrated in late MLP layers near the end of the network. Fine-tuning updated adapters and merged them into the base weights, so the shipped model looks ordinary.
Training data volume was small. In the smallest test, about 1% of training rows produced a trigger that fired most of the time while normal tool use stayed close to perfect, and the larger model used in the Codex CLI demonstration needed closer to one row in five.
The mechanism is a conditioned reflex, not stored code. The model learned the rule "see this phrase, emit this call", and the payload it points at lives on a server the attacker controls. The weights carry a URL, so the same poisoned download can point at a different script months later.
What the published sources do not provide is a way to read the trigger back out of those parameters. The researchers show where the change sits and how it was created, not a method for auditing an arbitrary download and proving it trigger-free.
How local AI model security is enforced at the agent layer
A model can only act through tools the agent hands it, so the separate switches for command execution and network access are where local AI model security is enforced. The model emits text; something downstream decides whether that text becomes a shell command with network reach.
OpenAI's Codex CLI documentation states that its default sandbox disables network access, uses Apple's Seatbelt sandbox on macOS, and combines a sandbox with a system call filter on Linux. That design means the exfiltration curl had nowhere to send data unless networking was enabled in configuration or approved at runtime.
ProjectDiscovery does not say which sandbox setting its demo ran under, and the sources read here do not test whether Codex CLI's default would have blocked the curl or paused for approval. Count the default as one layer and keep the others.
A short checklist applies to any agent wired to a downloaded model:
- Keep command execution and network access on separate switches, with network off unless a task needs it.
- Move API keys and SSH keys out of the working directory the agent can read, or load them only for the process that needs them.
- Prefer models with a verifiable publisher and training history, since inspecting weights for triggers is expensive and unsolved.
- Avoid disabling the sandbox and approval prompts to save time, and read each command before it runs.
Are local models only dangerous inside coding agents?
A model used purely for text generation has no filesystem and no network, so a trained reflex has nothing to reach. Chatting with a downloaded model on its own is a much smaller risk than wiring it to an execution tool, because reading and pasting its output is still a human decision.
The exposure starts when one process combines untrusted weights, a live shell, and a populated working directory. A poisoned model can pass every normal request and still ask for one command, and it only takes one approval.
That is also the reason the same weights can be harmless in one setup and dangerous in another. The agent configuration and the folder contents carry most of the risk.
How dangerous is a poisoned open-weights model in practice?
| Factor | What happened in the demo | What the evidence covers |
|---|---|---|
| Model | Open-weights coding model, fine-tuned trigger | Lab demonstration by ProjectDiscovery |
| Normal behaviour | 50 of 50 tool calls correct | Vendor-reported test |
| Trigger | "bonsoir, Elliot" in the prompt | Single phrase, attacker-chosen |
| Trained footprint | About 43M parameters, late MLP layers | Researcher estimate, not an audit method |
| Training cost | About $8 GPU time, under $50 total | Vendor-reported |
| Cleanup | Fine-tuning plus RL, backdoor survived | Equistamp study, published 2025 |
| Wild sightings | None reported in the sources read | Research risk, not a live campaign |
The distinction between demonstrated and observed matters. Malicious model files did appear in the wild in 2024, but those were pickle exploits rather than trained triggers. A trained-trigger backdoor is a risk researchers have shown is cheap to build.
FAQ
- Can a Safetensors file contain malicious code? No, the format stores tensor bytes and a JSON header with no instruction slot, so loading it does not execute anything. A Safetensors model can still carry a trained backdoor in its weights, which is a separate problem from file-level exploits.
- Does fine-tuning remove a backdoor? Usually not reliably. Equistamp's 2025 tests found ordinary backdoors firing up to one in five times after supervised fine-tuning and reinforcement learning, while backdoors designed to persist fired about three times in four at the middle model size.
- Is every uncensored model unsafe? Abliteration removes a refusal direction and does not add new behaviour, so the editing step itself is not the risk. The real question is who published the weights and what training data went into them.
- Would Codex CLI's default sandbox have blocked the attack? The sources do not say which sandbox setting the demo used. Codex CLI's documentation states the default sandbox disables network access, which would block the curl, but approval settings in your own configuration decide the outcome.
- What is the cheapest defense against a poisoned model? Treat the model as untrusted text, keep credentials out of its reachable directory, and leave network access off unless the task needs it.
Turning a careful security habit into written reference material
Security work rewards the habit of checking each assumption against a primary source, whether that is a repository file, an official document, or a study with dates and numbers attached. Dev doido readers and anyone following Crazystack typescript material tend to keep notes on exactly these checks, and those notes are usually more useful to other developers than another summary of a headline.
If the reasoning behind a check sits in a recorded walkthrough, turning that recording into an article with Skala Blog keeps the context intact: paste a YouTube URL, transcribe the video, and generate a draft you can review and edit.
For readers working through the tooling side of this problem, Crazystack is worth a look as a reference point for TypeScript-focused development work, alongside the primary security documentation that any credential-handling change should be checked against.
Fork this article
Start a new branch from the same video, shaped your way. You keep the credit; the original keeps the attribution.
A fork in another language is filed as a translation of this article, so the two pages point at each other. You can unlink it later from the editor.
0/240
You are creating
- Format
- For
- Language
- Source
- Your angle
You will be asked to sign in before it is generated.
Buy credits