Gen Threat Labs ran a controlled experiment. An AI agent was set up to read emails. Some of those emails contained untrusted content written to manipulate it. The agent then executed system commands, sent data outside its environment, and performed destructive file operations.
No software vulnerability was exploited. No CVE. The agent did exactly what it was built to do: read text and act on it.
The source is a BleepingComputer post, and I'll flag that it's a sponsored vendor piece promoting Gen's own products (Agent Trust Hub, Sage, Norton). The technical detail is high-level. I can't tell you the exact payload, the agent framework, or the email format, because the piece doesn't say. What it does describe is a pattern, and the pattern is real regardless of who's selling something next to it.
What happened, as far as we know
From the summary of the experiment:
- The agent had access to email, plus the ability to run system commands, touch files, and send data out.
- Untrusted content arrived in an email the agent was reading.
- The agent treated that content as instructions.
- It executed commands, exfiltrated data, and deleted or damaged files.
The post also cites two adjacent problems: malicious agent skills (12% of ClawHub skills at the time) and Warden Stealer, malware that targets AI assistant config files and tokens. Those are separate threats from the email experiment. I'm not going to speculate on how they connect to it.
Why this works at all
This is indirect prompt injection, and it works because of how LLM agents are built, not because of a bug in any one of them.
The model receives one stream of text. Your system prompt, the user's request, and the body of an email the agent just fetched all land in the same context window. The model has no hard boundary between "data I'm processing" and "instructions I should follow." An email that says something shaped like an instruction competes with the real instructions, and sometimes it wins.
The thing that turns this from an annoyance into an incident is the tooling. An agent that can only summarize email is a nuisance when injected. An agent with a shell, a filesystem, and an outbound network path is an insider with your credentials. The experiment hit all three: commands, exfiltration, destructive file operations.
The detection gap
Why do existing defenses miss this?
- Network and endpoint tools see an authorized process making authorized calls. The agent has legitimate access. Nothing about the traffic is anomalous at the packet level.
- Email security is built to catch malware, phishing links, and spoofed senders. A plain-text email whose only payload is a sentence aimed at a model looks like ordinary mail.
- The agent's own guardrails are the model deciding to refuse. That's the layer under attack, and it's probabilistic.
- Permissions help, but agents are usually granted broad access precisely because narrow access makes them less useful.
The gap is that nothing is inspecting the content between "email fetched" and "model acts on it."
Where Sentinel sits
Sentinel is an AI firewall. For agentic setups, it proxies the model traffic and scans tool results (which is what an email body is) before they return to the agent.
Here's how that would apply to this kind of attack, with the caveat that I haven't seen the Gen Threat Labs payload and can't claim Sentinel would have stopped that specific experiment. What I can describe is how the layers handle email-borne injection of this general shape:
-
Layer 0 (HTML extraction and hidden content). If the email is HTML, Sentinel strips it to text for scoring and separately pulls out content a human wouldn't see but a model would: HTML comments,
display:noneelements, white-on-white text, off-screen positioning. Those hidden sections get their own pass with a much lower block threshold. Hiding content from the reader but not the model has no legitimate purpose. - Layer 1 and 2 (decode and normalize). Base64, hex, URL-encoding, ROT13, and Morse get decoded and re-scanned. Invisible characters, bidi overrides, and homoglyphs get normalized before matching.
- Layer 3 (fast-path regex). Our library of regex patterns catches high-confidence signatures: authority hijacks like "ignore previous instructions," persona shifts, tool abuse patterns, and exfiltration phrasing like "POST this to https://...".
- Layer 4 (deep-path vector similarity). If the regex doesn't fire, the content is embedded and compared against our library of attack signature embeddings. This is what catches paraphrased injections that don't match a literal pattern.
- Layer 5 (secret detection, Teams and Enterprise). Independent of the above. If the agent reads a file containing credentials and the result heads back toward the model, API keys and tokens get redacted. That matters for the exfiltration half of this incident.
There's a related note for the Warden Stealer angle: that malware goes after config files and tokens. Secret redaction doesn't stop a stealer running on a host, so I won't pretend it does. It does mean a token that surfaces in a tool result doesn't reach the model in cleartext.
What a scan looks like
This is illustrative. The email text below is invented to show the shape of the attack, not the actual payload from the experiment.
Pointing an Anthropic SDK agent at the Sentinel proxy:
import anthropic
client = anthropic.Anthropic(
api_key="sk_live_...", # your Sentinel API key
base_url="https://api.sentinelaifirewall.com/v1",
)
# Tool results (like fetched email bodies) are scanned automatically
response = client.messages.create(
model="claude-sonnet-4-6", # your chosen model
max_tokens=1024,
messages=[{"role": "user", "content": "Summarize my unread email."}],
)
You need your own Anthropic key configured under Dashboard → Settings first; the proxy makes the upstream call on your behalf. Grok, OpenAI, and Gemini have equivalent routes.
If you'd rather scrub the email body yourself before handing it to your agent, use the direct endpoint:
import httpx
email_body = fetch_next_email() # untrusted by definition
r = httpx.post(
"https://api.sentinelaifirewall.com/v1/scrub",
json={"content": email_body, "tier": "strict"},
headers={"X-Sentinel-Key": "sk_live_..."},
)
result = r.json()
if result["security"]["action_taken"] in ("blocked", "neutralized"):
log_and_quarantine(result)
agent_input = result["safe_payload"]
For an email carrying an instruction aimed at the agent, an illustrative blocked response looks like this:
{
"request_id": "a1b2c3...",
"security": {
"action_taken": "blocked",
"threat_score": 0.91
},
"safe_payload": "[SENTINEL BLOCKED]: Article withheld — fast-path prompt injection detected. Matched: \"...\"."
}
Note that safe_payload on a block is a descriptive placeholder, not null. Branch on action_taken, but the placeholder is safe to log. In the agentic proxy, a blocked tool result is swapped for an inert placeholder transparently, and a neutralized one is wrapped in [SENTINEL-WARNING: ...] markers telling the model to treat it as untrusted data.
Two honest limits. The flagged action passes content through untouched and leaves the decision to you, so if you ignore flags you've bought a logger. And the descriptive-context exemption means a quoted example inside a news article won't hard-block, which is the right call for security writing but means you should read your flagged items.
What to do today
Treat every tool result as untrusted input, and scan it before the model sees it. An email body, a fetched web page, a file the agent opened: all of it is text an outsider may have written.
Then fix the second half of the problem. Check what your agent can actually do. If it can run shell commands, write files, and make outbound requests, ask which of those it needs for the job you gave it. Scanning reduces the odds an injection lands. Narrow permissions limit what happens when one does.
Sentinel's Starter tier is free (100 requests/month, no credit card). Try the scrub endpoint against your own agent's inputs at sentinelaifirewall.com.
Sources
AI-assisted draft or imaging, human-curated, reviewed and edited.
Top comments (0)