HACKR.GG
← Blog
AI Security2026-08-2713 min read

Prompt Injection Grew Up: How AI Agents Became a Real Attack Surface

Prompt injection stopped being a chatbot party trick the moment we gave models tools. Here's why it can't be patched the way SQL injection was, what the GitHub MCP heist and CVE-2025-6514 actually looked like, and the three-ingredient rule for telling whether your agent is exploitable.

Abstract illustration of a central node wired to many tools, with one corrupted red input line feeding into it

For about two years, prompt injection was treated as a party trick. You typed “ignore your previous instructions” at a chatbot, it said something it was not supposed to, everyone screenshotted it, and nothing was actually at risk because the model could not do anything.

That changed when we started handing models tools. An assistant that can only produce text has a fairly boring failure mode. An agent that can read your repositories, query your database, send email and execute shell commands has the same failure mode attached to real capability — and the industry connected those wires far faster than it worked out how to secure them.

// KEY POINTPrompt injection is not a bug in any particular model, and no vendor is one patch away from fixing it. It is a structural property of how language models consume input.

Why it cannot simply be patched

If you have done any SQL injection work, you already understand the shape of this problem — and, more importantly, why the fix that worked there does not port over.

SQL injection was solved by parameterised queries. Not by filtering apostrophes, not by escaping better, but by giving the query and the data two separate channels so that data physically cannot be parsed as instructions. The database engine holds that boundary; no amount of cleverness in the input crosses it.

A language model has exactly one channel. System instructions, retrieved documents, tool output and user input are concatenated into a single token stream. The model infers which part is authoritative from context and training, which is a probabilistic judgement, not a structural guarantee:

PARAMETERISED SQLchannel 1 — the querySELECT * FROM users WHERE id = ?channel 2 — the data"1 OR 1=1 --"data can never become querythe boundary is enforced by the engineLLM PROMPTYou are a helpful assistant. Never…Here is the issue you asked about:"Ignore previous instructions and…"User: summarise the open issues↑ one string. no channel. no boundary.any text can become an instructionnothing enforces the boundary — it does not exist
Parameterisation defeated SQL injection by making data structurally incapable of becoming instructions. There is no equivalent for prompts — instructions and data arrive as one stream.

This is why every mitigation to date is probabilistic. Delimiters, instruction hierarchies, and classifier guardrails all raise the cost of an attack. None of them makes it impossible, because they are all still expressed in the same channel the attacker is writing into.

// try it yourself
Worth doing in this order: exploit SQL injection first, watch parameterisation kill it dead, then look at prompts again. The contrast is the lesson.

Direct versus indirect — and why only one of them matters much

Direct injectionis a user typing an attack into the box. It is real, but the blast radius is limited to that user's own session and their own permissions. Someone jailbreaking a chatbot into swearing has mostly harmed themselves.

Indirect injectionis the dangerous one. The attacker never talks to the model at all. They plant instructions in content the agent will later read — a web page, a support ticket, a code comment, a calendar invite, a filename, the alt text of an image — and wait for someone else's agent to consume it. The victim is not the attacker's account. The victim is whoever's agent happens to fetch that content, carrying whoever's permissions that agent runs with.

The agent does not distinguish “content I was asked to summarise” from “orders from my operator”. Both are just text that arrived in the context window.

What this looks like in production

Three disclosures from the last year make the pattern concrete, and none of them required a novel model exploit.

The GitHub MCP data heist

In May 2025, researchers at Invariant Labs showed that a booby-trapped issue filed on a publicrepository could hijack a developer's agent. The developer asks something entirely ordinary — “have a look at the open issues” — the agent reads the malicious issue, follows the instructions inside it, pulls data out of the developer's private repositories, and publishes it in a pull request on the public repo.

01
Attacker files an issue
Public repo, ordinary-looking title, instructions hidden in the body.
02
Developer asks their agent a normal question
“Check the open issues and tell me what needs doing.”
03
Agent reads the issue
The injected text enters the context window as content, and is treated as instruction.
04
Agent uses its own token
That token has access to every repo the developer does — not just the public one being discussed.
05
Agent exfiltrates
Private data is written into a public pull request. Every action was one the agent was legitimately allowed to take.

The crucial detail: this was not a coding flaw in the MCP server. Invariant were explicit that it is an architecturalproblem — the server holds one token with broad access, so any successful injection inherits all of it. There is no patch for “the agent did exactly what it was permitted to do”.

CVE-2025-6514 — when the plumbing itself is vulnerable

Disclosed by JFrog in July 2025 and rated 9.6, this one is a more conventional bug in mcp-remote, the npm bridge used to connect clients to remote MCP servers. A malicious server returns a crafted authorization_endpointduring the OAuth flow, and the value is passed to the operating system unsanitised. On Windows that is full arbitrary command execution on the developer's machine.

# The class of bug is decades old.
# The context is new: it fires when a developer's
# tooling connects to an untrusted MCP server.

authorization_endpoint  ->  passed unsanitised to the OS
                        ->  command injection
                        ->  RCE on the developer's laptop

affected: mcp-remote 0.0.5 - 0.1.15
fixed in: 0.1.16

Note what this is: command injection. Not an AI vulnerability at all. The AI ecosystem simply built new plumbing quickly, and the new plumbing had the same bugs the old plumbing had in 2005.

// try it yourself
This is textbook command injection — exploit it against a live target in the Command Injection module and the CVE stops being abstract.

Tool poisoning and the supply chain angle

An agent picks which tool to call by reading each tool's description— text supplied by the tool's author. That makes tool descriptions an injection surface: a malicious server can describe its tool in ways that steer the agent, or quietly change that description after the user has already approved the server.

And because MCP servers ship as ordinary packages, they inherit ordinary supply chain risk. The postmark-mcp package is the clean example — fifteen legitimate releases, then a version that added silent exfiltration. Users had already vetted and trusted it fourteen versions earlier.

This is A03:2025 Software Supply Chain Failures wearing a new hat. The AI-specific part is only that the compromised package sits inside a loop with broad standing credentials and the authority to act.

The three-ingredient rule

The most useful way to reason about whether a given agent is actually dangerous is to check for three properties at once. An agent needs all three before injection turns into theft:

remove any one circle and the attack stops workingprivate datait can readuntrusted inputit ingestsan outbound channelit can write totheftis possible
An agent is exploitable when it can read something worth stealing, ingest content an attacker controls, and reach somewhere the attacker can collect from. Break any one and the chain fails.

This is genuinely useful in design review, because it converts an unsolvable research problem into a concrete architectural question. You are not trying to make the model injection-proof — you cannot. You are trying to make sure no single agent session holds all three properties simultaneously.

IngredientHow to remove it
Access to private dataScope the token to the one resource this session needs. The GitHub case was fatal precisely because one token reached every repository.
Untrusted inputUsually impossible to remove — reading external content is the point of the agent. Assume this one is always present.
An outbound channelRequire human approval for actions that leave the boundary: opening PRs, sending mail, outbound HTTP, writing to shared storage.
// THE FIXLeast privilege per session, not per integration. An agent that can only touch the repository currently being discussed cannot be talked into exfiltrating one it was never given.

What actually helps

Why this belongs in a pentester's skill set now

There is a temptation to file this under “AI stuff” and leave it to someone else. That is a mistake, because almost every real incident above resolves into a bug class that has been on the syllabus for twenty years.

The AI framingWhat it actually is
Prompt injectionUntrusted input crossing into a control channel — the same root cause as injection generally.
Excessive agencyBroken access control. The agent acted with permissions far wider than the task needed.
Tool poisoningSupply chain compromise, with a package that reached a trusted position first.
CVE-2025-6514OS command injection, unchanged since the 1990s, in new plumbing.
Agent data leakageAn exfiltration channel nobody enumerated during design.

The skill that transfers is the underlying one: knowing where a trust boundary is supposed to be, and testing what happens when input crosses it. Agents just moved the boundaries somewhere unfamiliar and handed them far more privilege than the old ones ever had.

// try it yourself
Our prompt injection labs run against a real model wearing a vulnerable system prompt — you get the flag by actually talking it out of the model, not by matching a canned answer.
// Practice this

Everything in this post has a hands-on lab on hackr.gg. Exploit it yourself right inside the lesson — no setup, no install, runs in your browser.

Open Prompt Injection course →
More posts
Web Security
OWASP Top 10 2025: What Actually Changed (and What It Means for You)
12 min
Identity
The Credential Nobody Owned: Machine Identities Are the Attack Surface of 2026
11 min
Teams
Security Training for Teams: Who It's For, and What Actually Changes
10 min