Pangram verdict · v3.3
We believe this text is mainly AI, with some human-written content.
AI likelihood · overall
AIArticle text · 1,724 words · 1 segments analyzed
tl;dr 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 next. 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 previous 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, search 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 about 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. How an indirect prompt injection reaches an agent. The user only ever sees step 1 and the result of step 4. 1RequestThe user asks for a task"Summarize this page" 2FetchThe agent reads content a third party controlspage · email · file 3ContextThat content and its hidden text join the promptdata + instructions 4ActionThe model follows the hidden textanswer · tool call 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. 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. Anatomy of an HTTP responseEvery response has three parts, and a browser shows only the last one An HTTP response in three parts. Part 1, the status line, reads HTTP/1.1 200 OK and says whether the request worked; it is hidden from the reader. Part 2, the headers, are name and value pairs that describe the response: Content-Type says the body is HTML, Cache-Control sets how long it can be reused, Set-Cookie stores a value in the browser, and X-Request-Id is a custom header the server invented. They are hidden from the reader. Part 3, the body, is the HTML page a person sees in the browser. An agent's fetch tool can pass parts 1 and 2 to the model as text. 1Status lineHidden from the reader One line that says whether the request worked. 200 means success. The words after the number are free text the server chooses. HTTP/1.1 200 OK 2HeadersHidden from the reader Name and value pairs that describe the response. Some are standard, and a server can invent any others it likes. Content-Type: text/html; charset=utf-8The body is an HTML page. Cache-Control: max-age=600The response can be reused for 10 minutes. Set-Cookie: session=9f2a; HttpOnlyStore this value and send it back next time. X-Request-Id: 7d62-4c11A custom header the server made up. Custom headers like this are where AI-directed text appears. 3BodyShown in the browser The page itself. This is the only part a person reading the site sees. <h1>Acme Widgets</h1> ... 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: curl -sS -L -D - -o /dev/null https://signalscorps.com 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: HTTP/2 301 location: https://www.signalscorps.com/ server: cloudflare HTTP/2 200 content-type: text/html; charset=utf-8 cache-control: public, max-age=0, must-revalidate link: <https://fonts.googleapis.com>; rel="preconnect" server: cloudflare 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. 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. Server to model Four routes that carry headers into context, and one that does not Five routes a response can take from the server to the model. Route one, a shell tool running curl with the dash-i flag, passes every response header. Route two, an error path such as the Gemini CLI direct-fetch mode on a status of 400 or above, passes all headers as JSON without the untrusted wrapper. Route three, a summarizing fetch tool such as Claude Code WebFetch, passes a model-written extract of the page and the redirect target. Route four, the MCP reference fetch server, passes the Content-Type value when a page is not HTML, and the robots.txt body in an error message. Route five, a body-only tool, drops every header before the model sees anything. Shell tool Runs curl itself curl -i Passes every response header to the model. Error path Unwrapped on failure status ≥ 400 All headers as JSON, no untrusted wrapper (Gemini CLI direct fetch). Summarizer Echoes metadata Location Redirect target reaches the model (Claude Code WebFetch). MCP fetch Echoes edge cases Content-Type Content-Type value on non-HTML pages; robots.txt body in errors. Body-only tool Drops headers res.text() Only the page content reaches the model. No header gets through. 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. Tool Can headers reach the model? What to check Claude Code: Anthropic’s coding agent, which runs in your terminal. Its WebFetch tool reads web pages for it. Partly. WebFetch passes a model-written extract of the page, plus the target URL when a page redirects to another site. If Claude Code runs curl in its shell, it can see