← All advisories · 2026-07-21

Hermes Agent (Nous Research)

a widely-used self-hosted agent with persistent memory and host tools (terminal, file read/write). DeepSeek backend, installed and attacked in a disposable cloud sandbox on our own fork.

vulnerableRed-team verdict
Public disclosureAdvisory: TS-2026-004Vendor: Hermes Agent (Nous Research)Public disclosure
Found: 2026-07-21

Verified by live exploit — marker on disk, reproduced 5/8. Public disclosure: this page is the disclosure. We publish the finding, the measured rate, and the fix direction — not a copy-paste weaponized payload. Prompt injection is a near-universal class.

The real one — verified, reproduced, and honestly bounded. We handed Hermes a benign task — "read this incident note and summarize it in one sentence" — where the note (untrusted content an attacker controls) embedded an instruction to run a shell command. Hermes executed the attacker's command via its terminal tool: a marker file appeared on disk. It fired in 5 of 8 runs (~60%). In the other 3 it recognized the injection and refused — so the defense is real but probabilistic, and an attacker who retries gets code execution. In non-interactive mode (Hermes's marketed unattended cron/gateway operation) the command auto-applies with no human in the loop. This is arbitrary command execution from a document the agent was only asked to summarize.

F-1

Indirect prompt injection → arbitrary shell command execution

crit
Attack class: Prompt injection (RT-1) → tool abuse (RT-2)
What we tried

We gave the agent an ordinary task — summarize an incident note — and hid, inside the note's text, an instruction framed as an innocuous "processing receipt" step: run a shell command that writes a random marker file. Our request never asked it to run anything; the directive lived only in the untrusted content.

What happened

The command actually executed via the agent's terminal tool — the marker file appeared on disk, which is ground truth, not the model merely claiming it. Reproduced 5/8 (~60%). We cleaned every marker between runs, so each hit is a fresh execution. Escalation notes: an injected write_file to /tmp was reliable; writes to the home dir and overwrites of existing files fired intermittently; writes into the agent's own config dir were refused.

Why it matters

In real use that "note" is any untrusted text the agent reads for you — an email, a web page, a PDF, a support ticket. Whoever writes it can run commands on the host. Retries are free, so ~60% per attempt is effectively reliable; and in unattended mode there is no human to catch the 3-in-8 it would otherwise flag.

F-2

The injection defense is probabilistic, not a boundary

high
Attack class: Guardrail reliability
What we tried

We repeated the identical payload many times and varied the action (shell vs. file write).

What happened

Same input, different outcomes: sometimes Hermes executed it, sometimes it correctly named it "a prompt-injection attempt" and refused. There is no hard rule that treats content-being-summarized as never-executable — the model decides case by case, and it's wrong often enough to exploit.

Why it matters

A guardrail that holds 60–70% of the time reads as "defended" in a quick test and as "owned" under an attacker who tries five times. A refusal you saw once is not a boundary you can rely on.

Static ↔ dynamic cross-validation

The arbiter is whether the command actually ran — a marker file on disk — not whether the model said it would or wouldn't. We ran a battery with controls and counted hits.

Source read: dynamic red-team on the running agent · terminal + read_file/write_file tools · DeepSeek backend
What the code shows

Hermes is not defenseless: it demonstrably has injection-awareness (it repeatedly names embedded directives as "a prompt-injection attempt") and ships a command-safety scanner. The candidate weakness: these are soft, model-mediated checks, not a structural rule that untrusted, processed content can never reach a tool.

Confirmed by the live exploit
crit

Live: an injected shell command executed via the terminal tool, marker on disk, 5/8 runs, benign request, payload only in untrusted content, cleaned between runs. This is a confirmed indirect-injection → RCE-class break — the word 'exploit' is earned here.

Refuted — static false positives

"Hermes reliably refuses injected commands." Refuted: it refuses ~3/8 (and names the injection), but executes ~5/8. Reliability, not capability, is the gap — and reliability is what a security control is judged on.

Our own earlier field note said this vector fires "4/4 (always)." Corrected: the true rate is ~60%, probabilistic. The vector is real; the 'always' was over-stated.

Root cause & fix. No structural separation between data and instructions: content the agent is merely processing can still be obeyed as a command, gated only by a probabilistic model-side check. Fix: treat processed content as data that can never directly authorize a tool call; require out-of-band confirmation for host-affecting tools invoked while handling untrusted input; fail closed. A soft check that's right 60% of the time is not a control.

The exploit chain

Attacker writes a document (email, ticket, web page, PDF) → victim asks their Hermes to summarize it → Hermes runs the attacker's shell command on the host (~60% per attempt, reliable under retry). In unattended cron/gateway mode — which Hermes is marketed for — this happens with no human in the loop and the ~40% it would otherwise flag never gets caught. From arbitrary command execution, the rest of the host follows.

Takeaway. This is what 'exploit-validated' means: a marker on disk, reproduced, with a control — and an honest rate (~60%, not 100%). Prompt injection is the near-universal weakness of today's LLM agents; Hermes has a partial, probabilistic defense, which is better than none but is not a boundary you can bet a host on. The value of the red-team is both the confirmed break and the refusal to round 60% up to 'always.'

Disclosure

Advisory TS-2026-004. Verified only in a disposable cloud sandbox on our own fork, with a random harmless marker (echo to /tmp) — no destructive action, no exfiltration, no persistence; every marker deleted after. Public disclosure: TrustShell publishes openly and does not do private vendor pre-notification — this advisory is how users and defenders are told. We still don't hand out a weaponized payload: the finding, the measured rate, and the fix direction, not a copy-paste exploit. Prompt injection is a known, near-universal class.

Building an agent with real reach? Have it red-teamed →