Back News.Ycombinator Prompt injection in HTTP headers: what 217M web responses show
We read the HTTP response headers of 217,097,223 page responses from Common Crawl, 10% of its September 2026 crawl of 2.17 billion pages, and looked for any header written for an AI system. 7,959 sites sent one. Almost all of them point agents to another resource, such as an llms.txt file or an MCP server. A small number try to give the agent orders. Whether any of it reaches your model depends on which parts of the response your fetch tool passes along, so the defense starts there.
7,959 sites sent a header aimed at AI. Writing to agents through headers is already routine, so treat headers as part of what your agents read.
7,271 of those sites sent pointers, and 6,989 of them sent x-llms-txt . A pointer is the server telling your agent where to go . Check that your agents treat those destinations as new, untrusted fetches.
30 sites sent injection attempts, 24 of them in a header named X-AI . Most were pranks. The few that ask for real actions only work when the agent holds the matching power, such as a shell or database access.
139 sites sent a header recording whether they had classified the client as an AI bot, and 136 of them said it was one. Servers already tell agents and people apart, which is the step that agent-only content needs. Audit important sites with an agent’s user agent.
Some sites use headers to push back on agents. Two put strings named after Anthropic’s test triggers in protest-named headers such as X-AI-Makes-Us-Dumber , and one warns hacking agents away on its error pages. Expect your agents to meet text written to stop them as well as to steer them.
283 distinct header names were aimed at AI, and 1,709 more sites matched our AI keywords without being AI-directed. A detector that matches on names alone would have flagged 910 of those sites by mistake. Alert on what the agent does after a fetch.
In our October 2026 tests, Claude Opus, Claude Sonnet, and Claude Haiku running in Claude Code found our test headers and did not act on them by default, and everyday tasks such as an uptime check were enough to put the headers in front of them. When the user’s prompt told them to follow the site’s directions, they obeyed in 7 of 9 runs, so the refusal depends on how much authority your prompts give a site.
A route most research misses
Most research into prompt injection on the web looks at the page itself. Palo Alto Networks Unit 42 studied injections on live pages and listed ten ways to deliver them, from zero-size text to URL fragments. None of the ten uses response headers. In its data, social engineering made up 85.2% of jailbreak methods, and the header injections we found fit that: plain “ignore all instructions” text with no concealment, because browsers never show headers anyway.
Google’s Threat Intelligence Group searched Common Crawl page text and sorted what it found into harmless pranks, helpful guidance, optimization, deterring AI agents, and malicious. Our header injections lean the same way: 22 of the 30 sites sent pranks, and a few sites used headers to deter agents.
So how at risk are agents today? Models are getting better at spotting injected text, but they still follow some of it. In Anthropic’s 2025 tests of Claude for Chrome , attacks succeeded 23.6% of the time without its mitigations and 11.2% with them, so even a hardened agent acted on roughly one attempt in nine. The real risk for any agent comes down to two questions: can hostile text reach its model, and what can the agent do when some of it gets through?
This post asks those questions of a route most defenses ignore: the HTTP response headers a server sends with every page. A person reading the page never sees them, but an agent’s tools can pass them straight to the model. We end with what our scan says the risk today. To see why it matters, start with how indirect prompt injection works.
Indirect prompt injection
Indirect prompt injection is an attack in which instructions reach an AI agent inside content it reads for someone else: a web page, an email, a file, or a tool result. It works because a language model reads its instructions and its data as one stream of text. When you ask an agent to summarize a page, your request and the page land in the same context window, and nothing in the text marks which part may give orders. The user never wrote the injected instructions and usually never sees them. The term comes from a 2023 paper by Greshake and colleagues , and OWASP ranks prompt injection first in its Top 10 for LLM applications.
The sequence below shows one attempt from request to result.
What step 4 can do depends on the agent’s permissions. A summarizer can only give a skewed answer. An agent that can send email, edit files, or run commands can act on the injected text.
What a response header is
When a browser or an agent requests a URL, the server sends back three parts: a status line that says whether the request worked, a block of header fields that describe the response, and the body, which is the HTML, JSON, or file you asked for. RFC 9110 defines this shape. Headers carry metadata such as the content type, caching rules, and cookies, and a browser shows almost none of them to the reader.
The figure below is a short, benign response. The body is the only part a person sees in the browser window.
You can see the hidden part of any response yourself. This command sends a normal GET request, prints the headers of every response, follows redirects with -L , and discards the body. Swap in any URL you want to inspect:
Against our own site it returns two responses, trimmed here to the main fields. The first redirects the bare domain to www , and the second is the page itself:
All of that is text a fetch tool could pass to a model. A server can invent any header name it likes, and even the reason phrase on an HTTP/1.1 status line is free text, which RFC 9112 tells clients to ignore.
How headers reach the model
A header only matters to an agent if the agent’s fetch tool copies it into the model’s context. Many tools do not. The ones that do fall into four routes, shown below with a fifth route that drops headers before they arrive.
So the question for your own setup is which tool your agent fetches pages with. The table below shows, for common agents and tools, whether response headers can reach the model and what to check.
We ran the MCP fetch server and curl against our canary server . The other rows come from vendor documentation or from reading each tool’s code at the version linked. The short rule: a tool that returns only page text closes this channel, and a shell can open all of it.
AI headers are already common
Headers aimed at AI are already common, and almost all of them are pointers. Of the 7,959 sites in our scan that sent a header addressed to AI, 7,271 used it to point agents to another resource: an llms.txt file, an agents.md file, an MCP server, or an agent skill. One header, x-llms-txt , accounts for 6,989 of those sites.
Even a benign pointer is a steering channel. It is a server telling your agent where to go , including to MCP servers the agent might connect to. Most pointers today lead to documentation. The same header could lead to a file full of instructions or a tool server the site owner controls.
This chart counts each site once, under the most serious label any of its headers received.
The eight guidance sites sit between pointers and injections. Half tell an agent how to use the site without overriding it, for example by asking it to prefer a JSON API over scraping the HTML. One steers a little harder and invites agents to fetch an endpoint:
Defenders are starting to use the same channel. One site sends this warning with an error response:
The header names we found
The 7,959 sites used 283 distinct header names aimed at AI. A few names dominate each group. This table lists the most common, by the number of sites that sent each one.
The detection group also includes x-verified-* headers, such as x-verified-claude-user and x-verified-chatgpt-user , that record whether a request came from a named AI fetcher.
Some AI-directed headers are legitimate signals, and that is why name matching fails. The IETF’s AIPREF draft defines a Content-Usage header that states a usage preference such as train-ai=n . Cloudflare adds Content-Signal and x-markdown-tokens to the Markdown it serves to agents through Markdown for Agents . Beyond those, 1,709 sites matched our AI keywords with headers that have nothing to do with AI: content security policies, cache directives, and plugin flags whose names happen to contain ai or llm .
How servers can misuse them
Each group of headers gives a site owner a different lever over an agent. None of them causes harm by itself. Each needs an agent capability to turn text into an action.
Pointers steer the agent
A pointer names the place to go. An llms.txt file can hold instructions written for agents, an MCP server offers tools to call, and an agent skill is a package of instructions and scripts to install. The harm scales with what the agent does . An agent that only reads gets more text to weigh. An agent that can connect to new MCP servers or install skills can end up running the site owner’s tools.
Detection enables agent-only cloaking
139 sites sent a header recording whether they had classified the client as an AI bot, and several named the crawler they detected. A server that can tell an agent from a person can send each a different response. Agents make that easy: OpenAI, Anthropic, and Perplexity publish their user-initiated fetcher names, ChatGPT-User , Claude-User , and Perplexity-User , and Cloudflare’s Markdown for Agents announcement notes that Claude Code and OpenCode send Accept: text/markdown .
The security firm SPLX showed what cloaking does . It served different content to AI agents based only on the user agent. In a five-candidate hiring test, the cloaked candidate scored 88 and ranked first when the AI read the résumé the server chose to show it, and 26, last, from the real one. Cloaking needs no agent capability at all. It changes what the agent reads and keeps that content out of a manual review of the same URL.
Descriptions read as facts
Policy headers such as x-ai-crawl: allowed state permissions. Others describe the content, and a model can take the description as fact. x-ai-content-type: human-authored is a claim the site makes itself, and an agent that ranks, cites, or screens content may repeat or reward it without checking. This needs no capability beyond writing an answer, and the harm is a wrong or skewed one.
Instructions ask for action
The last group addresses the agent directly and tells it what to do. These are the injection attempts in the section. They are the only group whose text asks for an action, and each one needs a specific power to succeed.
The injection attempts we found
30 sites sent a header that tries to override, redirect, or steer an AI, and 24 of them used a header named X-AI . A site can send more than one kind, so the counts below add up to more than 30. Each example below is a header observed in our sample. Anything shown as [REDACTED: …] is our edit: we removed site names and any value that would work if copied, such as a command, an encoded payload, or a trigger string. None of them needs a flaw in the model to work: each needs an agent that reads headers and holds the power the text asks for, and removing either one leaves the header inert.
22 sites sent a joke instruction. These are some of the values we saw:
A prank needs nothing beyond an agent reading the header. The cost is a useless answer or a wasted run, and it shows the channel works.
One site added a SQL injection string to the joke:
This only does damage if the agent can write to a database and its code passes model text into a query unescaped. That is two failures at once, and both sit in the application.
Five sites sent strings named after Anthropic’s test triggers. All five carried the refusal trigger, a value built to make Claude refuse, and one of them also sent a related trigger for redacted thinking. Two sites used a header named X-Anthropic , both with a shortened copy of the refusal string, and one used X-AI-2 . The other two put the strings in headers whose names are protests: X-LLM-Abuse on one site, and X-AI-Eats-The-Planet and X-AI-Makes-Us-Dumber on the other. The X-AI-Eats-The-Planet value is the redacted-thinking trigger.
Nick Frichette showed that with Claude 4 models the refusal string ended any request whose context contained it, and because conversation history is replayed, the session kept failing. Anthropic patched that behavior in May 2026. On an affected model it needed nothing else: reading the header was enough to stop the agent. The protest names suggest these site owners want to stop the AI agents that visit them. Tracebit used the same idea for defense with “context bombs” , strings planted to trip the guardrails of offensive agents.
One site sent a Base64-encoded value. Decoded, it asks the agent to identify itself to an outside site:
It needs a fetch tool the agent can point at any URL. The payoff for the site is knowing which model you run, which helps it tailor what it serves .
One site posed as a security check and asked the agent to act:
This needs a shell that can run npx , which downloads and runs a package the site chose. It is the most dangerous pattern in our sample, because the “fix” is the attack. The same site also sends a second version that tells the agent to POST a report to an outside endpoint. An agent that sent it would confirm to the site that it obeys header instructions.
A fake applicant score
Two sites sent the same value, so it looks like a pattern. It reads as a verdict for an AI hiring screener:
It needs a screening workflow whose agent reads response headers. The harm is a skewed hiring decision that nobody sees the reason for.
Common Crawl is a public archive of the web, published one crawl at a time. Alongside the raw pages, each crawl ships WAT files: compressed JSON metadata for every capture, including the HTTP response headers the server returned. We used crawl CC-MAIN-2026-39 , which Common Crawl describes as 2.17 billion pages from 40.4 million hosts . It has 100,000 WAT files, and we took every 10th one. That gave 10,000 files spread evenly across the crawl, holding 217,097,223 page responses, or 10% of its pages. One crawl is itself a monthly sample of the public web, so read our counts as rates within that sample: roughly one AI-directed site per 27,300 pages, and one injection site per 7.2 million pages.
For each response, we kept a header as a candidate when any of these was true:
its name is one of 41 header names already reported carrying AI-directed text (listed below);
its name contains an AI term as a whole word, such as ai , llm , gpt , claude , or mcp , or contains instruction or directive ;
its value names an AI system and also reads like an instruction, with words such as “ignore”, “you must”, or “respond”.
The full story
This article is one source in a clustered incident — the cluster page carries the summary, timeline and every other outlet covering it.
