SafePrompt · Prompt injection detection API
Get a free API key
SafePrompt
Prompt injection detection API for LLM apps and agents.
Back to blog
Ian Ho
9 min read

Hermes Agent Prompt Injection: The Four Inputs It Reads

Web pages, MCP tool results, files and chat messages all reach the model. Four injection paths, three tested payloads, and where the check goes.

Prompt InjectionHermes AgentMCPAI Agents

Key points

Hermes Agent is the open-source agent from Nous Research, MIT licensed, at v0.21.2 as of 11 September 2026. It reads text you did not write: web pages through web_extract, results from every MCP server you connect, files it opens mid-task, and messages from Telegram, Discord, Slack, WhatsApp and Signal. Its built-in injection scanner covers context files, not those four runtime inputs. SafePrompt reads that text at the boundary and blocks the instruction before the model acts on it.

Your agent reads a page, and the page reads back

You ask Hermes to summarise a deployment guide. It calls web_extract, pulls the page, and hands you four tidy bullets. Nothing else happens.

Now picture the same agent a month later. The gateway is running on Telegram, a filesystem MCP server points at your project, and a cron job checks your repository every morning. The page it fetches carries an HTML comment written for the assistant, not for you.

Same fetch. Very different morning.

Quick Facts

Project:Hermes Agent, Nous Research, MIT licensed
Current release:v0.21.2, published 11 September 2026
Injection scanning scope:Context files: AGENTS.md, .cursorrules, SOUL.md
MCP tool results:Invisible Unicode TAG characters stripped

What does Hermes Agent actually read?

More sources than most setups track. Hermes Agent is the open-source agent built by Nous Research, released under the MIT licence, with v0.21.2 published on 11 September 2026 (read from the repository release list on 12 September 2026). It runs as a terminal app or as a gateway process, and it keeps working while you talk to it from a phone.

The Hermes tools documentation lists the categories that pull in outside text: web_search and web_extract for the open web, read_file and the terminal for local content, browser automation for rendered pages, and MCP server tools for everything you connect.

Two features extend the blast radius of anything that lands in that context. Skills are written to disk and reloaded later, and the built-in cron scheduler runs jobs unattended with no human in the room. Text read once can therefore act more than once.

Where does a prompt injection enter Hermes?

Injection enters in four places, and none of them is your own typing. Direct injection arrives in the message you send. Indirect injection arrives later, inside data the agent already decided to trust, which is the harder half of the problem and the one an agent framework creates by design.

  1. Web pages. Anything web_extract or the browser tools return. The author of that page is a stranger.
  2. MCP tool results. Issue bodies, support tickets, database rows, documents and search hits, returned through whichever servers you list under mcp_servers.
  3. Files opened during the task. A vendored repository, a downloaded PDF, a README in a dependency you have never read.
  4. Gateway messages. Telegram, Discord, Slack, WhatsApp and Signal. Allowlists and DM pairing control who may speak to the agent, and they do not inspect what the approved person forwards.

The MCP path has a public worked example. On 8 July 2025, Rez Havaei, Rex Liu and Maximilian Li of General Analysis published a demonstration in which a support ticket carried a note addressed to the assistant, asking it to read the integration_tokens table and post the contents back into the ticket.

A developer asked their agent to show the latest open ticket. The agent read the planted text through the Supabase MCP server and ran both queries.

Two details are worth keeping straight. This was a researcher demonstration, not a breach reported in the wild, and the write-up says so. The mechanism is still the ordinary one: a privileged agent read attacker-authored text that arrived as data and treated it as an instruction.

What does the built-in scanner already cover?

The scanner covers a real and specific surface, described in the project's own security documentation (read on 12 September 2026). Context files are scanned for prompt injection before they are included in the system prompt, and the page names them: AGENTS.md, .cursorrules and SOUL.md. A blocked file is dropped with a warning and never loaded.

The same page lists what those checks look for, including instructions to disregard prior instructions, hidden HTML comments, attempts to read credential files, exfiltration by curl, and invisible Unicode. It then states the limit plainly: these patterns are heuristics, not semantic intent detection.

Hermes carries several other controls that do their job well. URL-capable tools validate destinations against private ranges and cloud metadata addresses, and treat a DNS failure as blocked. MCP subprocesses receive a filtered environment.

Dangerous commands go through an approval gate, and scheduled jobs default to denying them.

One control is easy to over-read, and getting it right is the difference between a guess and a design. The MCP documentation states that invisible Unicode TAG characters in the U+E0000 to U+E007F range are stripped from tool results, resource content and tool descriptions. That closes a smuggling channel at the character level.

An instruction written in plain visible English inside a ticket body passes through it untouched, because there is nothing hidden about it.

What happens when you send a real payload?

SafePrompt reads the text and returns a verdict before the agent sees it. We took three payloads shaped like the paths above, sent each to the production API on 12 September 2026 at strict sensitivity, and recorded what came back.

PayloadWhere it arrivesVerdictThreat returned
Deploy guide with an HTML comment telling the assistant to post the contents of a credentials file to a paste siteweb_extractsafe: falsesocial_engineering
Issue body claiming maintainer authority and asking the agent to paste its configuration into a commentMCP tool resultsafe: falsejailbreak_instruction_override
Repository convention file telling the agent to omit the credential-handling section from any summaryFile read mid-tasksafe: falsejailbreak_instruction_override
Ordinary developer question about a deploy region flagUser messagesafe: truenone

Sent to the production API on 12 September 2026, sensitivity strict.

The fourth row matters as much as the first three. A check that stops a poisoned page and also stops the question you actually asked is a check you will switch off by Friday.

Where does the check go in a Hermes setup?

SafePrompt sits where untrusted text becomes tool output, which is the last point you control before the model reads it. Validate the string your own MCP server is about to return, the page body your fetch step just pulled, or the inbound message your gateway just received. Hermes connects to stdio and HTTP MCP servers listed in config.yaml, so a server you wrote is a natural home for the call.

// Validate the tool result before returning it to the agent
const res = await fetch('https://api.safeprompt.dev/api/v1/validate', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-API-Key': process.env.SAFEPROMPT_API_KEY,
    'X-User-IP': endUserIp,
  },
  body: JSON.stringify({ prompt: toolResultText, sensitivity: 'strict' }),
})

// Fail closed: an unavailable check is not a passing check.
if (!res.ok) throw new Error('Validation unavailable')

const { safe, threats, reasoning } = await res.json()
if (!safe) {
  return { content: 'Content withheld: this source carried instructions for the agent.', threats }
}
return { content: toolResultText }

Two details decide whether this works in practice. The key stays server side, never in a variable your client bundle can read, and X-User-IP carries the address of the human driving the session rather than your own server, because the API returns a 400 without it. If you prefer a package to a raw call, npm install safeprompt gives you new SafePrompt({ apiKey }) and .check(), and the raw call is the canonical form because it works from any language.

The response is designed to be branched on. safe is the verdict, threats names what was found, confidence scores the call, and reasoning explains it in a line you can log. Handle a threat label you do not recognise by refusing, since the list grows.

What SafePrompt covers

SafePrompt protects the payload. Anything coming into your AI that could compromise it, we read first and block. We do not police what your users are allowed to ask, which is why ordinary messages go straight through.

Read at the integration boundary, across messages, documents and tool results:

  • Instruction override and claimed authority, including the polite and bureaucratic phrasings
  • Role-play jailbreaks and extraction imperatives aimed at your system prompt
  • Obfuscated and multilingual variants, and hidden Unicode
  • Poisoned documents, tickets, issues and pages that arrive as data
  • Sandboxing, command approval and file permissions stay in your app and in Hermes, which is why ordinary traffic passes

Put the check in front of your agent today

One POST, four fields back, 10,000 free validations a month with no card. SafePrompt is built and run by Ian Ho, and it has one job.

Frequently asked questions

Can Hermes Agent be prompt injected?

Yes, through any text it reads that someone else wrote. Hermes Agent pulls web pages with web_search and web_extract, receives results from every MCP server you connect, opens files with read_file, and accepts messages from Telegram, Discord, Slack, WhatsApp and Signal through its gateway. All of that text reaches the model in the same context as your own instructions. An attacker who can write into any one of those sources can write instructions the agent may follow.

Does the Hermes Agent context file scanner stop prompt injection?

It covers a specific surface. The Hermes security documentation describes scanning of context files, naming AGENTS.md, .cursorrules and SOUL.md, before they are included in the system prompt. The same page lists the patterns it looks for and states that they are heuristics, not semantic intent detection. Web pages, MCP tool results and files opened during a conversation arrive after the system prompt is built, so a check on runtime text is a separate job.

Does Hermes Agent strip hidden characters from MCP tool results?

Yes. The Hermes MCP documentation states that invisible Unicode TAG characters in the U+E0000 to U+E007F range are stripped from tool results, resource content and tool descriptions, while legitimate emoji tag sequences such as regional flags are preserved. That closes a smuggling channel at the character level. A malicious instruction written in ordinary visible English inside a ticket, issue or document is untouched by it, which is why the text also needs to be read for intent.

Where should a prompt injection check sit in a Hermes Agent setup?

At the point where untrusted text becomes tool output. Validate the string your MCP server is about to return, the page body your fetch step just pulled, and the inbound message your gateway just received, before any of it is handed back to the agent. A single POST to https://api.safeprompt.dev/api/v1/validate with the X-API-Key and X-User-IP headers returns safe, threats, confidence and reasoning, and the caller returns a refusal instead of the content when safe is false.

Has an MCP prompt injection like this happened in the real world?

Researchers at General Analysis published a working demonstration on 8 July 2025. Rez Havaei, Rex Liu and Maximilian Li submitted a support ticket whose body addressed the assistant directly and asked it to read the integration_tokens table and post the contents back into the ticket. A developer then asked their coding agent to show the latest open ticket, the agent read the planted text through the Supabase MCP server, and it ran both queries. The write-up describes a researcher demonstration, and no breach in the wild was reported. The leaked rows landed in the same thread the attacker was already watching.

Further reading

Protect Your AI Applications

Add the check before you need it. SafePrompt reads every message, document and tool result going into your model and blocks the attacks, in one line of code.

Add SafePrompt as a preferred source on Google. You tick one box on Google's own page. Google then shows you more of our posts in your own results.