Real Prompt Injection Attack Examples in Production Tools

Four disclosed prompt injection chains in Salesforce, GitHub, ChatGPT and Grafana. In every one, the channel that leaked the data was a protection the vendor had already built.

Published: Sep 8, 2026

13-19 mins

By Grace

The real prompt injection attack examples in this post are not lab demos. All four were found in products that were already deployed and in daily use, all four were reported to the vendor and fixed, and all four share something that is easy to miss when you read them one at a time: the data left through a security control that was already in place and doing roughly what it was designed to do.

That is a different story from the familiar one, in which an AI tool with no guardrails reads something nasty and does what it is told. In these four, the guardrails existed. An allowlist. An image proxy. A domain validator. A model trained to refuse. Each one narrowed the path data could take on the way out, and each one turned out to be the path.

Case The instruction came in through The existing control that carried the data out
ForcedLeak (Salesforce Agentforce) A Web-to-Lead form, in the Description field The Content Security Policy allowlist, via a domain on it that had expired
CamoLeak (GitHub Copilot Chat) A pull request description, using GitHub’s hidden-comment feature Camo, GitHub’s own image proxy
ShadowLeak (ChatGPT Deep Research) An email the victim never opened OpenAI’s own servers, where the agent runs
GrafanaGhost (Grafana AI) An external resource referenced from logs The image render path, after the URL validator was fooled

ForcedLeak: the attack that arrived through a sales lead form

Salesforce’s Agentforce can answer questions about leads. Leads arrive through Web-to-Lead forms, which exist so that strangers on the internet can type things into your CRM. In July 2025 researchers at Noma Labs asked the obvious question: what happens if the stranger types instructions instead of an enquiry?

They went through the form’s fields looking for one with room to work in. First Name allows 40 characters. Company allows 40. Email allows 80. The Description field allows 42,000, which Noma’s write-up marks as “Optimal” for the job. A short field limits an attacker to a sentence. A 42,000 character field lets them write a program.

The payload then sits there and waits. It does nothing until an employee does something entirely normal, like asking the AI to summarise the new lead. At that moment the assistant reads the employee’s question and the attacker’s instructions in the same breath, and cannot tell which is which.

Getting data out was the hard part, and it is the part that matters here. Salesforce ran a Content Security Policy that limited which domains the agent could reach, which is exactly the control you would want. Noma read the list and found my-salesforce-cms.com on it. The domain had expired. It was available to buy, and they bought it for five dollars.

I should admit something at this point. I have never once opened a URL allowlist in a tool I administer and read what was on it. Until I read Noma’s write-up it had not occurred to me that the list was mine to check, or that an entry on it could quietly stop being the thing it used to be.

Noma is blunt about how load-bearing this was: “Without bypassing the Content Security Policy, data exfiltration would have been impossible, making this discovery one of the most critical components of the entire vulnerability chain.” The allowlist was not bypassed by cleverness. It was bypassed by a lapsed renewal.

Noma reported it on 28 July 2025 and rated the chain CVSS 9.4. Salesforce began enforcing Trusted URLs for Agentforce on 8 September 2025, before the research went public on 25 September, and re-secured the expired domain. Customers were covered by an enforcement change they did not have to make themselves.


CamoLeak: how a pull request leaked private source code

GitHub Copilot Chat can read a repository to answer questions about it, which includes reading pull request descriptions. In June 2025 Omer Mayraz of Legit Security put a prompt in one and then went looking for somewhere to hide it.

He did not have to improvise. GitHub documents a way to hide content inside comments, and Mayraz’s write-up says so with visible delight: “Luckily, GitHub came to the rescue with a proper solution: invisible comments are an official feature!” The hidden text still triggers the normal pull request notification to the repository owner. The content of it appears nowhere.

One of the real prompt injection attack examples in practice: GitHub's own documentation showing that hiding content inside comments is an official feature

GitHub documents the hiding place. The prompt was not smuggled past a filter; it was placed using a feature that works as designed.

I use GitHub and I did not know this was a documented feature.

The next detail is the one people underestimate. The person who planted the prompt and the person it acts on are different people. Mayraz notes that “the user who asked Copilot Chat to explain the PR is different from the user who posted the invisible prompt, demonstrating that the prompt can affect any user who visits the page.” Copilot runs with the permissions of whoever is reading, so the attacker inherits the reviewer’s access to private repositories.

Then the exfiltration, which is the best trick in any of these four. Images in GitHub’s interface are fetched through a reverse proxy called Camo, and Camo will not fetch a URL that was not signed in advance. An attacker cannot generate a signed URL on the fly for an address containing stolen data. Mayraz’s answer was to pre-generate a Camo URL for every letter and symbol in the alphabet, hand that dictionary to Copilot inside the injected prompt, and ask it to render the secret as ASCII art made of images. Every image was a one pixel transparent file on his server. The data came out in the order the pictures were requested, one character at a time, through GitHub’s own protective proxy.

He reported it through HackerOne. GitHub’s fix, applied on 14 August 2025, was not to make Copilot more resistant to injection. GitHub disabled image rendering in Copilot Chat completely. The chain was rated CVSS 9.6.


ShadowLeak: an attack your network monitoring never saw

The two above end with data crossing a network, which means there is at least a chance somebody’s tooling notices. Radware’s ShadowLeak removes even that.

ChatGPT’s Deep Research agent runs in OpenAI’s cloud rather than on your machine. Radware found that an attacker could send the user an email carrying hidden instructions, and when the agent later processed the mailbox it would follow them and send data out from OpenAI’s own servers. The victim never had to open the message. What the attack does need is a user who has pointed the agent at their mailbox in the first place, which is the ordinary way the feature is used. Radware’s researchers describe it as “the first purely server-side sensitive data leak”, performed “autonomously from OpenAI servers”.

The consequence is the reason this one belongs in the list: “Unlike previously disclosed zero-click attacks, ShadowLeak operates independently and leaves no network level evidence, making these threats nearly impossible to detect from the perspective of the ChatGPT business customer.” Your firewall sees nothing because nothing crossed it. Your endpoint agent sees nothing because the endpoint was not involved. The work happened on infrastructure you do not run, which is the thing you were buying.

Radware reported it to OpenAI on 18 June 2025 and OpenAI notified them of the fix on 3 September 2025, roughly eleven weeks later. (Several write-ups say the fix landed in early August. Radware’s own disclosure section gives 3 September, and that is the date used here.)

For how hidden instructions get into an email in the first place, direct vs indirect prompt injection covers the mechanics; this post is about what happened after they arrived.


GrafanaGhost: three defences, defeated one after another

Grafana sits on top of exactly the data you would not want walking out: infrastructure telemetry, financial metrics, customer records. Its AI features had protections against prompt injection. On 7 April 2026, Noma Security published a chain that went through them.

The first attempt failed, and Noma says so plainly. The obvious move is to have the assistant render an image with the stolen data in its URL, and it did not work: “Result: Blocked. The application had implemented content security policies or domain restrictions that prevented loading images from external domains.” A working control, doing its job.

They tried a second route that worked but needed a click, and rejected it themselves: “User interaction introduces friction, reduces the severity of the finding, and makes it less likely to succeed in the wild.” So they went back to the controls one at a time.

The image validator was written to allow only relative URLs and data URIs. Noma read the JavaScript and found the flaw was one string test: the check used startsWith() without validating the scheme. A protocol-relative URL, the kind written //noma-labs.com/image.png, begins with a slash, so it passes a startsWith('/') test while a browser reads it as an absolute address on somebody else’s server. In Noma’s words, “The function would see this as a ‘relative URL’ and allow it, but the browser treated it as an absolute URL to an external domain.” A one character misunderstanding of what counts as local.

The model’s own refusal was the last obstacle, and it fell to a single word. Noma’s write-up names it: “By intercepting the model’s thought process, we discovered that including the keyword \”INTENT\” in our indirect prompt effectively disabled/bypassed the model’s security guardrails. The presence of this keyword seemed to signal to the model that the instruction was legitimate.” Not a jailbreak paragraph. One token that read as authority.

Sasi Levi, vulnerability research lead at Noma Labs, told CyberScoop what that leaves a security team with: “The exfiltration happens through a channel the AI itself initiates, which looks like normal AI behavior to any observer. Traditional SIEM rules, DLP tools, and endpoint monitoring aren’t designed to interrogate whether an AI’s outbound call was instructed by a user or by an injected prompt.”

Grafana disagrees with the framing, and that disagreement is part of the story. Joe McManus, CISO at Grafana Labs, told CyberScoop the company disputes “the claim that this finding constitutes either a ‘zero-click’ attack or that it could operate silently, autonomously, or in the background”. In his account, a successful attack “would have required significant user interaction: specifically, the end user would have to repeatedly instruct our AI assistant to follow malicious instructions contained in logs, even after the AI assistant made the user aware of the malicious instructions”. He adds that there is no evidence of exploitation in the wild and that no data was leaked from Grafana Cloud. On the process both sides agree: Noma’s own write-up thanks Grafana, saying they “jumped on the issue immediately, worked closely with us to validate the findings, and rolled out a fix as fast as possible”.

Both accounts can be read together without picking a winner. A researcher describes the shortest path they could construct. A vendor describes what a real user would have had to ignore along the way. My own habit is to read the vendor’s response before deciding how alarmed to be, because it is the half that says what the attack required of the victim.


What four real prompt injection attack examples have in common

Two things, and neither is the one you would guess.

The untrusted content came in through the front door. A Web-to-Lead form exists so that strangers can submit text. A pull request description exists to be read. An email exists to arrive. None of these four involved a user carelessly pasting something from a sketchy website. The usual advice to be careful about what you feed an AI tool is sound, and it has no purchase here, because feeding the tool stranger-written text is the entire function of the product.

The exfiltration channel was a security control. An allowlist that had a lapsed domain on it. An image proxy that only fetches pre-signed addresses. A domain validator. A model trained to refuse. Each one narrowed the way out, and the narrow way out is what carried the data.

This is where a reader who knows the lethal trifecta may feel a contradiction, so it is worth being precise. That model says an assistant is exposed when it can reach private data, is exposed to untrusted content, and can communicate outward, and that removing any one of the three closes that route. It is right. What these four show is that narrowing a channel is not removing it. An allowlist still communicates outward, to a shorter list. A proxy still fetches images, through one hop. Reduce the outbound channel to a single trusted path and you have not closed the route; you have concentrated it, and made whoever controls that path very important. In ForcedLeak, controlling it cost five dollars.

There is a third thing they share, and it is the closest thing to good news here. Look at what each vendor changed in response. GitHub removed a feature. Salesforce enforced its allowlist properly and repurchased the domain. OpenAI fixed it inside its own infrastructure. Grafana patched the render path. Every one of those fixes was made on the vendor’s side of the line. Noma did tell Salesforce customers to go back and audit recent lead submissions and agent interactions, so there was cleanup to do, but the thing that closed the hole was not a customer setting.


Questions to ask before an AI tool reads untrusted input

The honest takeaway is smaller than the four stories suggest, and pretending otherwise would be the usual mistake. Most of what went wrong here was the vendor’s to fix, and the vendor fixed it. In ForcedLeak the mitigation that protected customers was an enforcement change Salesforce made on its own side.

What is left for you is a question rather than a configuration. For each AI feature you have switched on, ask whether it does both of these things: read content that people outside your organisation can write, and reach the internet on its own. If both are true, that feature is in the same category as the four above, and the useful follow-up is what the vendor does on the outbound side. Not “is your model resistant to prompt injection”, a question that invites the answer yes, but where the assistant can send data, who maintains that list, and what happens when an entry on it expires.

I ran that check on my own setup while writing this, and the useful part was not the answer. It was how long it took me to be sure of the answer.

Two of the tools I use most were quick, because I have no AI features switched on in either WordPress or Notion. One qualifies plainly: I have folders from my own machine connected to Claude Cowork, and it reads things on the web when I ask it to, which is both conditions in a single tool. Then I got to browser extensions and the answer stopped being clean. I installed several a while ago, including one that summarised YouTube videos. I rarely open them now and I assume most are disabled. I have not checked.

That is the honest finding, and it is not the tidy one. A summariser reads a page somebody else wrote and sends it somewhere to be processed, which is the same shape as everything above. The gap that matters is not between a safe setup and a risky one. It is between what I believe my setup is and what it actually is, and closing that gap took one sentence to describe and I still have not done it.

Detection is a partial answer at best, and prompt injection detection covers why the numbers are worse than the marketing. If you are choosing between AI vendors on more than this one question, vetting AI vendors has the longer version.


FAQ

Q

Have any of these prompt injection attacks been used against real companies?

None of the four disclosures reports a victim. All four were found by security researchers, reported to the vendor privately, and fixed before or around publication, which is the normal shape of responsible disclosure and the reason these read as case studies rather than breach reports. Only Grafana went further and said so outright, that there was no evidence of its bug being exploited in the wild and that no data was leaked from Grafana Cloud. The other three vendors did not make that statement either way, so treat the absence of a known victim as what it is: no one found one, which is not the same as proof that no one was hit.
Q

Why did my AI assistant show me a prompt injection instead of following it?

Because surfacing it is one of the behaviours vendors build in, and it sometimes works. In the GrafanaGhost disagreement, Grafana’s CISO said a successful attack would have required a user to keep instructing the assistant to follow the malicious content “even after the AI assistant made the user aware of the malicious instructions”. If your assistant flags odd text it found in a document or a log, that is the intended behaviour, and the important part is what you do next rather than that it happened.
Q

How do prompt injection vulnerabilities like these get found and fixed?

Through the same channels as ordinary software bugs. CamoLeak went to GitHub through HackerOne and was fixed on 14 August 2025. Radware reported ShadowLeak to OpenAI on 18 June 2025 and was told of the fix on 3 September. Noma reported ForcedLeak to Salesforce on 28 July 2025, and enforcement of Trusted URLs shipped on 8 September, before public disclosure on 25 September. Weeks to months, privately, then a write-up.
Q

Will my company’s security monitoring catch an attack like this?

Probably not, and two of the four disclosures say so directly. Radware’s point about ShadowLeak is that a server-side leak leaves “no network level evidence”, so there is nothing for your tools to see. Noma’s point about GrafanaGhost is that SIEM, DLP and endpoint monitoring “aren’t designed to interrogate whether an AI’s outbound call was instructed by a user or by an injected prompt”. The request looks like the assistant doing its job, because it is the assistant doing its job.

Sources

Each incident is described as its researchers and the affected vendor stated it at the time of disclosure. Where the two accounts differ, as with GrafanaGhost, both are given.

Written by Grace

I test AI tools and agents in my own workflow, and write down what I find, including the settings that surprised me. About Grace and how posts are verified

Leave a Comment