An Offensive Security Overview of the HTTP QUERY Method
If you have written an API in the last fifteen years, you already know the problem QUERY was invented to solve. You needed to send a read request with a filter too complex to fit in a URL, so you did what everyone does: you sent a POST /search and pretended it was a read. It worked. It also quietly threw away every guarantee the protocol gives you about safe, idempotent, cacheable requests.
In June 2026 the IETF standardized a fix. RFC 10008, The HTTP QUERY Method (published June 15, 2026) defines a method that is safe and idempotent like GET, but carries a request body like POST, the first genuinely new HTTP method since PATCH landed in RFC 5789 back in 2010.
Most of the coverage you have seen frames this as a developer experience win. It is. But this post is written for the other side of the table. Because the same three properties that make QUERY convenient, a new method, a request body, and a cache key computed over that body, line up almost perfectly with the three oldest and most productive bug classes in the HTTP stack. QUERY does not invent new vulnerabilities. It reopens old ones, all at once, on infrastructure that has never been tested against them.
Let’s walk the whole surface.
Before the details, here is the frame to keep in your head for the rest of the post:
QUERY is the worst case combination for a defender. It must be inspected like a
POST(arbitrary body, CSRF, size limits) and cached like aGET(poisoning, deception), and almost no intermediary in the wild treats it as both yet.
Everything below is an elaboration of that sentence.
You had exactly two options before QUERY, and both of them lie to some part of the stack.
GET with everything in the URL is semantically honest, safe, idempotent, cacheable, but the query has to live in the URL:
GET /users?role=admin&status=active&dept=eng&perm=read&perm=write HTTP/1.1
That breaks the moment your filter gets large or deeply nested. URLs have practical length ceilings (~8 KB on most stacks), nested structures encode horribly, and, this is the part that matters later, the RFC explicitly notes that a URI is more likely to be logged or otherwise processed by intermediaries than the request content. Your filter ends up in access logs, browser history, Referer headers, and bookmarks.
POST /search solves the body problem and lies about everything else. Nothing in the protocol tells an intermediary that the request is read only, so caches won’t cache it, proxies assume side effects, and automatic retry logic refuses to replay it. You bought a body and paid for it with every safety guarantee.
QUERY closes the gap. From RFC 10008 §1, the method is:
- Safe, the client does not request or expect a state change (same semantic contract as
GET); - Idempotent, it can be replayed after a dropped connection without worrying about partial state;
- Cacheable, and here is the load bearing sentence for this entire post, the cache key incorporates the request content.
That last property is where we spend most of our time. Hold onto it.
You will see blog posts claiming “Node has supported QUERY since 2024.” That is technically true and precisely misleading, and the distinction matters because the maturity of the surrounding infrastructure is itself an attack signal. The more recently a method was bolted onto a parser, the more likely two hops in a request chain disagree about how to handle it, and disagreement is the raw material of both smuggling and cache poisoning.
Here is the actual lineage:
| Date | Milestone |
|---|---|
| Nov 2008 | RFC 5323 (WebDAV SEARCH), the direct ancestor: a safe, idempotent method carrying an XML body |
| 2019 | Asbjørn Ulsberg reopens the idea in the HTTP community (credited in the RFC’s acknowledgements) |
| Mar 2021 | draft-ietf-httpbis-safe-method-w-body-00, originally named “HTTP SEARCH” |
| 25 Jan 2024 | nodejs/node issue #51562, the earliest concrete implementation demand in a mainstream runtime |
| ~Feb 2024 | Node 21.7.2 (via an llhttp update) begins parsing QUERY natively; stable support lands on the 22.x LTS line |
| 15 Jun 2026 | RFC 10008 published as a Proposed Standard, registered in the IANA HTTP Method Registry |
So the earliest public demand to implement is the Node issue from January 2024, opened while pointing at draft-02. But the idea is a direct descendant of WebDAV’s SEARCH from 2008. The takeaway for testing: a target’s Node version tells you whether the runtime even understands the method, and “the runtime parses it” is not the same as “the framework routes it,” which the Express issue tracking QUERY support demonstrated the hard way.
If you want a mental model: you are testing a method that is simultaneously seventeen years old as a concept and eighteen months old as production code. That gap is where the bugs live.
The combination new method + body + cache touches the three most lucrative HTTP layer bug classes in bug bounty history. The next three parts each get their own deep dive, but here is the map:
- Request smuggling / desync, a new method that half the chain parses differently → front end/back end disagreement.
- Cache poisoning / deception, the cache key now includes an attacker controlled, unbounded body → inconsistent normalization.
- CSRF / the “safe” trap, “safe” in the spec does not mean “no side effects” in the implementation.
Before diving in, credit where it is due, because you should know whose research you are standing on, and because the QUERY story is a story about reincidence, not new territory.
- Amit Klein, today a professor at the Hebrew University of Jerusalem; formerly VP of Security Research at SafeBreach and CTO of Trusteer. He authored the original web cache poisoning research in 2004 and co authored the original request smuggling paper in 2005.
- Chaim Linhart, Amit Klein, Ronen Heled, and Steve Orrin, the Watchfire team (Watchfire was later acquired by IBM) who wrote the seminal 2005 paper.
- Régis “Regilero” Leroy, reawakened the technique in 2015 to 2016 (“Hiding Wookiees in HTTP,” DEF CON 24) during the decade it lay dormant.
- James Kettle (
albinowax), Director of Research at PortSwigger, makers of Burp Suite. He repopularized smuggling at modern scale in 2019 and pushed cache poisoning forward. He has presented at Black Hat for a decade. - Omer Gil, coined “Web Cache Deception” in 2017.
- sw33tLie, bsysop, Medusa, and Jeppe Weikop, full time bug hunters behind the most recent desync primitives (TE.0 in 2024, TE.TE in 2025), later consolidated by Kettle.
A lot of recent writing credits nearly all of this to Kettle. That is inaccurate, and if you cite it that way in a report you will lose credibility with anyone who knows the field. The honest attribution:
| Technique | Actually originated by | Kettle’s role |
|---|---|---|
| Request smuggling | Linhart, Klein, Heled, Orrin, Watchfire, 2005 | Revived it at modern scale (2019) |
| Web cache poisoning | Amit Klein, “Divide and Conquer” (2004) | Practical Web Cache Poisoning (2018), Web Cache Entanglement (2020) |
| Web cache deception | Omer Gil (2017) | Independent of Kettle |
| Smuggling revival | Regilero (2015 to 2016), then Kettle (2019) | Gave it scale and tooling (Burp) |
| TE.0 dechunking | sw33tLie / bsysop / Medusa (2024) | N/A |
| TE.TE / 0.CL | Jeppe Weikop / Kettle (2025) | Consolidated in “HTTP/1.1 Must Die” |
The bridge to QUERY: the method does not create any of these classes. It opens a new axis, an unknown method carrying a body that gets cached, where all three can recur at once.
Request smuggling, the modern name is desync, was first documented by the Watchfire team in 2005. The mechanism has not changed since:
An HTTP request passes through a chain of servers, front end (CDN / proxy / WAF) then back end (origin). Each hop has to know where one request ends and the next begins. On HTTP/1.1 that boundary is defined by two framing headers: Content-Length and Transfer-Encoding. When two hops disagree about that boundary, an attacker can hide a second request that only one of them sees. That smuggled request skips the front end’s rules (WAF bypass) and prepends itself to the next victim’s request.
If you want the canonical modern treatment, Kettle’s HTTP Desync Attacks: Request Smuggling Reborn (2019) is the paper that repopularized the class, and HTTP/1.1 Must Die (2025) is the current state of the art, the latter reporting desync vectors affecting tens of millions of sites and earning roughly $350,000 in bounties, including CVE-2025-32094 against Akamai.
Smuggling needs two things: (1) a parsing disagreement between hops, and (2) a place to hide the smuggled request. QUERY hands you both.
The disagreement is close to guaranteed. QUERY is a new method. A modern CDN forwards it; a legacy WAF or load balancer might reject it, ignore it, or, most usefully, treat it differently from how the origin does. As one analysis of the RFC’s attack surface put it, older WAF, proxy, framework, and load balancer policies may not recognize QUERY yet; some stacks reject it, others route or inspect it differently than POST. Every one of those inconsistencies is an exploitable seam.
The hiding place is built in. Unlike GET, QUERY has a legitimate body. Historically, servers that accepted a body on a bodyless method (“fat GET”) were a smuggling and cache poisoning vector, and Kettle’s long standing advice was simply don’t support fat GET. QUERY standardizes exactly that shape, a body bearing, cacheable, safe method, but now with a spec that requires the body to be read. The anti pattern is now the standard.
And the whole CL.TE / TE.CL / TE.0 / TE.TE family, the four “length interpretations” Kettle enumerates in the 2025 paper (CL, TE, implicit zero 0, and HTTP/2’s H2), applies directly, except now against parsers that may never have been fuzzed with a QUERY verb.
Here is the part worth being precise about, because it is easy to picture the attack incorrectly. The smuggling does not happen “inside” the JSON body of the QUERY. It happens one layer above the body, in the framing of the HTTP message: the Content-Length / Transfer-Encoding headers and the unknown method name.
Division of labor:
- The unknown method confuses the parser (does this hop route a QUERY? reject it? fall back?).
- The QUERY body is the hiding place for the smuggled request.
- The JSON itself is just the façade that makes the outer request look like an innocent search.
There is a telling detail in the spec here. RFC 10008’s Security Considerations never once use the word “smuggling.” That is not an oversight, smuggling is a failure of intermediary implementation, not of the method’s semantics, so it is genuinely out of the RFC’s scope. But from an offensive standpoint, an un addressed gap in a brand new method is exactly where you want to be looking.
A QUERY.TE desync, front end honors Content-Length, back end honors Transfer-Encoding:
QUERY /search HTTP/1.1
Host: target.example
Content-Type: application/json
Content-Length: 118
Transfer-Encoding: chunked
5c
{"q":"laptop","filters":{"price":{"lt":500}}}
0
QUERY /admin/users HTTP/1.1
Host: target.example
X-Ignore: x
What happens, step by step:
- Two framing headers conflict.
Content-Lengthsays 118 bytes;Transfer-Encodingsays “read in chunks.” RFC 9112 §6.3 requiresTransfer-Encodingto win and theContent-Lengthto be stripped, but not every hop obeys. - The front end honors
Content-Length. A legacy WAF/proxy reads 118 bytes, forwards the whole thing as one QUERY request, and waves it through, it looks like an ordinary search. - The back end honors chunked. The origin reads the
5cchunk, hits the terminating0, and treats the remainder as a second request:QUERY /admin/users. - Result: WAF bypass. The second request never passed the front end’s rules. The “search body” was the smuggled request’s hiding place.
Viability depends on the specific proxy↔origin pair, so test the front end and origin in isolation and compare how each frames the message. The structural fix is the one Kettle has been arguing for since 2025: HTTP/2 end to end, including upstream. Note that most stacks terminate HTTP/2 at the edge and downgrade to HTTP/1.1 upstream, which, as the paper points out, is even more dangerous than HTTP/1.1 end to end because it introduces a fourth length interpretation. That downgrade is where QUERY based desync will live.
If smuggling is the recycled classic, cache poisoning is the structural, new risk in QUERY, because the RFC deliberately moves the cache key into the body.
Cache poisoning was first described by Amit Klein in 2004 (“Divide and Conquer: HTTP Response Splitting, Web Cache Poisoning Attacks, and Related Topics”) and deeply developed by Kettle in Practical Web Cache Poisoning (2018) and Web Cache Entanglement (2020).
A cache stores responses so the origin isn’t hit every time. To find the right stored response, it computes a cache key. Traditionally that key is URL + a few headers. Two requests with the same key get the same stored response. Poisoning is the art of storing a malicious response under a key that a victim will also generate, so the victim receives the attacker’s content.
Kettle’s central lessons from Entanglement are worth quoting in spirit: components that look safe because they sit in the cache key become dangerous when they are parsed, transformed, and normalized inconsistently between cache and application. His two pieces of standing advice: rewrite the request, not the cache key, and don’t support fat GET.
Read RFC 10008 §2.7 and you will see the spec do, by design, exactly what Kettle spent years warning against:
- The cache key incorporates the request content, attacker controlled, effectively unbounded.
- To improve efficiency, the RFC explicitly permits caches to normalize the body before keying: “caches MAY remove semantically insignificant differences from request content,” for instance by removing content encodings or “normalizing based upon knowledge of format conventions, as indicated by any media subtype suffix in the request’s
Content-Typefield (e.g.,+json).”
And the RFC is candid about the consequence. In its own words, if a cache applies a different normalization model from the origin, two distinct queries can be treated as equivalent, causing the wrong response to be returned. That is a poisoning primitive described in the specification itself. As one write up of the spec noted, in multi tenant systems this kind of mistake becomes a serious vulnerability.
Every permitted normalization is a potential discrepancy. It is the “fat GET” hazard, now standardized and spread across a much larger, more structured space than headers ever offered.
The most likely first vector is divergent JSON normalization. Consider a duplicate key:
Attacker’s request:
QUERY /products HTTP/1.1
Host: shop.example
Content-Type: application/json
{"q":"tv", "q":"<script>evil()</script>"}
Victim’s request:
QUERY /products HTTP/1.1
Host: shop.example
Content-Type: application/json
{"q":"tv"}
The chain of events:
- Duplicate key on purpose. The JSON contains
qtwice. JSON parsers disagree on duplicate keys, some take the first value, some the last. If the cache and origin resolve it differently, you have your discrepancy. - Cache keys on the first
q. The cache normalizes toq=tv, the same key the victim will generate. To the cache, the two requests are identical. - Origin processes the second
q. The origin executes with the malicious payload and returns a contaminated response, which the cache stores under thetvkey. - Victim gets the payload. Anyone searching
tvis served the poisoned response from cache. One request, impact on everyone.
Beyond duplicate keys, the variations to test are exactly the “semantically insignificant differences” the RFC invites caches to collapse: field reordering, whitespace, ambiguous Unicode, and numeric forms (1 vs 1.0 vs 1e0). The bug exists any time the cache and the origin disagree about what counts as “the same body.”
The same “body = key, no size limit” property opens two further doors, both raised by researchers in the public discussion around the RFC:
Cache busting / flooding. The key is unbounded and attacker controlled. Vary a single byte and you force a miss:
QUERY /search → {"q":"a","_":"rnd-0001"}
QUERY /search → {"q":"a","_":"rnd-0002"}
QUERY /search → {"q":"a","_":"rnd-0003"} ...
Either every request misses the cache and full load returns to the origin (a cost amplification DoS), or you flood the cache with millions of unique entries and evict the legitimate ones.
Cache deception, the sibling attack Omer Gil disclosed in 2017 against PayPal (also presented at Black Hat USA 2017). Here you trick the cache into storing a sensitive, personalized response under a key the attacker can also generate, and then read the victim’s cached data. With QUERY this gets worse via the Location / Content-Location mechanism: RFC 10008 §2.4 lets a QUERY response point at an equivalent GET able resource, and if that temporary URI is predictable or leaks the query, it becomes a direct target.
If you test GraphQL, this section is where the abstract risk becomes concrete for a real ecosystem, with a caveat worth stating up front: this is a candidate future, not a shipped one.
GraphQL has always used POST for reads, because queries don’t fit in a URL, which meant giving up HTTP caching. The GraphQL over HTTP spec already supported GET plus persisted queries as a partial workaround, and on paper QUERY solves the problem cleanly: a full body and native cacheability. But “solves it cleanly on paper” is not the same as “adopted,” so it is worth being precise about where things actually stand.
I fetched the current GraphQL over HTTP spec draft directly while writing this, and it does not mention the QUERY method anywhere. GraphQL over QUERY is not part of RFC 10008 either: the RFC defines the method, not the payload formats that ride on top of it, and whether or how GraphQL clients adopt QUERY is a separate, still open discussion.
What exists today is enthusiasm, not commitment. When RFC 10008 hit Hacker News and generated over a hundred comments, GraphQL came up almost immediately, multiple commenters pointed out that QUERY is a natural semantic fit for GraphQL queries (as opposed to mutations, which are not safe). That is community agreement that the fit makes sense, not a roadmap commitment from the GraphQL Foundation.
The most concrete engineering signal so far actually comes from outside GraphQL itself. Spring Framework’s pull request adding RFC 10008 support ran straight into the fact that @QueryMapping already exists as an annotation in Spring GraphQL. Maintainer Brian Clozel’s response: “We will do a thorough review of this PR and synchronize with other Spring projects… there are many aspects to consider (like the fact that @QueryMapping already exists in spring graphql) but we would like to support this in time for Spring Framework 7.1 in November.” A companion issue tracks the core RequestMethod support separately. That is a real team doing real coordination work, but it is plumbing for the HTTP method in general, not a GraphQL over QUERY announcement.
As one analysis of the RFC put it plainly: “the current GraphQL over HTTP draft has not adopted QUERY; using it in practice means waiting for GraphQL servers, clients, CDNs, and frameworks to support it,” and adoption across that whole chain, servers, CDNs, reverse proxies, and browsers, is honestly “a multi year road,” not a next quarter one.
So treat what follows as conditional. The risk does not exist yet because the transport does not exist yet for GraphQL specifically. It exists the day a GraphQL server, framework, or gateway starts accepting QUERY, and given the semantic fit and the Spring precedent, that day is a matter of when, not if. That is exactly why it belongs in a recon checklist now rather than after it ships everywhere.
But making GraphQL cacheable at the edge would reactivate risks that non cacheable POST is currently, accidentally, masking.
First, the term you’ll want defined precisely. A batching attack exploits GraphQL’s ability to send multiple operations in a single HTTP request. A rate limiter that counts “requests per second” counts one, but the origin executes N operations. Checkmarx’s write up shows the canonical abuse: 100 login attempts in a single request, sailing past a per request rate limit:
[ {"query":"mutation{login(u:\"joe\",p:\"pass1\"){token}}"},
{"query":"mutation{login(u:\"joe\",p:\"pass2\"){token}}"},
... x100 ]
Wrap that in a QUERY that the WAF treats as a safe, cacheable read, and it gets even quieter. The OWASP GraphQL Cheat Sheet documents batching, depth, and alias based abuses in more depth.
The risks that compound specifically with QUERY:
- Poisoning of a cached query, divergent normalization of the GraphQL body serves one user’s response to another. This is the Part 5 vector, aimed at GraphQL.
- Complexity / depth bombs, a deeply nested query that looks cheap but is expensive to resolve. If it’s cacheable and the key varies, every request pays full cost, a cost DoS.
- Introspection + cache, an exposed schema accelerates recon, and a mis keyed cache lets you reuse or enumerate responses.
This is the newest frontier, and the least explored, so it’s worth staking out early.
Agent tools, the retrieval side of protocols like MCP and agent to agent messaging, that fetch data are, semantically, queries, not mutations. Until now the transport couldn’t say so: a read and a write from an agent looked identical to everything between the agent and the data. QUERY gives retrieval its own method, safe, idempotent, and cacheable, which is genuinely useful, and genuinely a new attack surface.
Why agents amplify the risk. They retry automatically (idempotence invites it), and they send large, structured bodies, embeddings, metadata filters, reranking parameters. That maximizes both the cache benefit and the collision surface.
The key offensive implication: context poisoning via the HTTP cache. If an agent’s retrieval (RAG) layer speaks cacheable QUERY, poisoning that cache entry injects false data straight into the model’s context, without touching the prompt or the model. The HTTP cache becomes a manipulation vector for the agent.
A sketch of the PoC:
QUERY /rag/retrieve HTTP/1.1
Host: agent-backend.example
Content-Type: application/json
{"embedding":[0.12,0.98,...],"topk":5,"filter":{"doc":"policy"}}
- The attacker discovers the cache key behavior of that endpoint (is the body normalized?) and forces a collision with the agent’s legitimate query.
- Under that key, they seed a “retrieved document” containing false facts or injected instructions.
- On the next identical retrieval, the agent is served the poisoned content from cache and treats it as trusted context.
If you do offensive work adjacent to LLM systems, this is where the QUERY story stops being a rehash of 2005 and becomes something new.
The most likely developer mistake, and an easy find on a real target.
“Safe,” per RFC 9110 §9.2.1 and reaffirmed in RFC 10008, means only that the client does not request a state change, not that the implementation has no side effects. Those are very different claims.
Search endpoints frequently have hidden side effects: writing to a “recent searches” table, updating a last_seen timestamp that feeds rate limiting, incrementing a counter, or firing analytics with real downstream consequences:
QUERY /search HTTP/1.1
{"q":"laptop"}
| non-obvious side effects:
+-> INSERT INTO recent_searches(...)
+-> UPDATE user SET last_seen = now()
If a CSRF middleware only guards the classic list (POST / PUT / DELETE / PATCH), a QUERY endpoint with a side effect walks straight through, the same class as GET based CSRF, on a method nobody has thought to audit yet.
The spec’s partial mitigation, and its limits. RFC 10008’s Security Considerations note that QUERY is not on the WHATWG Fetch CORS safelist, so browser JavaScript must send a preflight OPTIONS, the same as PUT or DELETE. That closes the naïve “smuggle a cross origin body past CORS because the method looks like GET” attack in conforming browsers. But it does not cover same origin requests, non browser clients, server to server calls, or servers that answer the preflight permissively (Access-Control-Allow-Methods: ..., QUERY). And as one analysis stresses, the practical risk isn’t the spec, it’s whether every hop in your chain actually handles the preflight and the eventual QUERY consistently.
One structural observation before the checklist. The decision “this is cacheable and safe” is not made by the application, it’s made at the edge (CDN, reverse proxy, WAF). And it is not a coincidence that two of the largest CDNs wrote the standard.
RFC 10008’s authors are Julian Reschke (greenbytes), James M. Snell (Cloudflare), and Mike Bishop (Akamai), the same J. M. Snell who, sixteen years earlier, co authored RFC 5789 (PATCH). Edge cacheability is a CDN’s core business; the parties who profit most from “complex searches become cacheable again” are also the ones carrying the weight of computing that body inclusive cache key correctly.
There’s a useful precedent here. Cloudflare already “hacked” POST caching via the Workers Cache API: compute a SHA 256 of the body, turn it into a synthetic GET key. That is precisely what QUERY standardizes, which means the bugs of that manual pattern (hash computed wrong, body not fully read, normalization diverging from origin) migrate into the native implementation. My working hypothesis for where to hunt first: custom Workers / cache key configurations where a developer normalizes the QUERY body differently from the origin. And because CDN level support tends to ship before framework support, that edge↔origin gap, the classic desync terrain, will be wide open during the transition.
A test plan you can lift straight into an engagement scope.
Recon / discovery
OPTIONSthe endpoint → checkAllow:forQUERY.- Look for the
Accept-Queryresponse header (advertises support and accepted media types). - Send a blind
QUERY; a405 + Allowor415 + Accept-Queryconfirms or denies support. - Map
POSTendpoints that are really reads:/search,/filter,/report,/graphql.
Smuggling / desync
- Compare a
QUERYsent directly to the origin vs. through the CDN. QUERY+Transfer-Encoding: chunked(and chunk extensions, à la TE.TE).- Conflicting
Content-LengthandTransfer-Encoding. - HTTP/2→1.1 downgrade on the upstream hop.
Cache poisoning / deception
- Find a cache oracle (detectable hit/miss).
- JSON: duplicate keys, reordering, whitespace, ambiguous Unicode, numeric forms.
- Cache busting: loop unique bodies, measure origin load.
- Inspect
Location/Content-Locationfor predictable or leaking URIs.
CSRF, AI, and agents
- QUERY endpoints with observable side effects not covered by CSRF.
- Permissive preflight? Same origin and non browser paths.
- RAG / GraphQL endpoints migrated to QUERY.
- Poison a retrieval cache → context poisoning.
The defensive half, so your write up closes the loop:
- Explicit method allowlisting in WAF / gateway / LB, QUERY handled deliberately, never by accidental fallback.
- POST level body scrutiny, the same SQLi/XSS/injection rules and size limits applied to the QUERY body.
- Correct cache key, hash the full body; normalize identically between cache and origin, or don’t normalize at all. Kettle’s mantra: rewrite the request, not the cache key.
- CSRF coverage for any QUERY endpoint with side effects, regardless of the “safe” designation.
- HTTP/2 end to end, including upstream, the only structural fix for the request boundary ambiguity.
- Restrictive preflight, don’t add QUERY to
Allow-Methodswithout need; keep sensitive data out of temporaryLocationURIs.
QUERY is a genuinely good addition to HTTP. POST /search was always a lie, and the method finally matches the meaning. But “good for the web” and “safe by default” are different claims, and the gap between them is where you work.
Three things to carry into your next engagement:
- The body is the new battleground. Smuggling uses the QUERY body as a hiding place and the HTTP framing as the ambiguity. Cache poisoning uses the body as a poisonable key.
- The transition window is the moment. Fragmented adoption, CDN yes, framework no, means maximum disagreement between hops. This is when the bugs surface.
- Prioritize AI and the edge now, and keep watching GraphQL. AI and RAG retrieval endpoints are where the first real QUERY deployments are being born, that’s where the newest impact, context poisoning, has no established defenses yet. GraphQL is still a candidate, not a shipped target, but it is the natural next one to watch given the semantic fit and the early framework coordination already underway.
The RFC didn’t invent a new attack. It reopened three old ones, standardized the anti pattern that fuels them, and shipped it to infrastructure that has never been tested against it. Go find them, on systems you’re authorized to test.
Specifications
- RFC 10008, The HTTP QUERY Method (Reschke, Snell, Bishop; June 2026). See §2.4 (Location), §2.7 (Caching), §3 (Accept-Query), §4 (Security Considerations).
draft-ietf-httpbis-safe-method-w-body, the working group draft history (originally “HTTP SEARCH,” 2021).- RFC 5323, WebDAV SEARCH (2008), the method’s ancestor.
- RFC 5789, PATCH Method for HTTP (Dusseault, Snell; 2010).
- RFC 9110, HTTP Semantics and RFC 9112, HTTP/1.1.
Request smuggling
- Linhart, Klein, Heled, Orrin, HTTP Request Smuggling (Watchfire, 2005).
- Amit Klein, HTTP Request Smuggling in 2020: New Variants, New Defenses and New Challenges (SafeBreach, Black Hat USA 2020).
- James Kettle, HTTP Desync Attacks: Request Smuggling Reborn (PortSwigger, Black Hat / DEF CON 2019).
- James Kettle, HTTP/1.1 Must Die: The Desync Endgame (PortSwigger, Black Hat / DEF CON 2025).
Cache poisoning & deception
- Amit Klein, Divide and Conquer: HTTP Response Splitting, Web Cache Poisoning Attacks, and Related Topics (2004).
- James Kettle, Practical Web Cache Poisoning (2018) and Web Cache Entanglement: Novel Pathways to Poisoning (Black Hat USA 2020).
- Omer Gil, Web Cache Deception Attack (2017) and the Black Hat USA 2017 white paper.
Ecosystem & analysis
nodejs/node#51562, the earliest recorded implementation demand (Jan 2024).- GraphQL Performance and Security docs; OWASP GraphQL Cheat Sheet; Checkmarx, GraphQL batching attack.
- GraphQL over HTTP spec draft, current as of writing; does not mention the QUERY method.
- Spring Framework PR #34993, adds core RFC 10008 support, surfaces the
@QueryMappingnaming conflict with Spring GraphQL; and the tracking Spring Framework issue #36988. - Hacker News discussion of RFC 10008, where GraphQL’s fit for QUERY was raised immediately by commenters.
- laioutr, RFC 10008: What the New HTTP Method Means for Frontends, source of the “multi year road” framing on cross ecosystem adoption.
- Cloudflare Workers Cache API.
- Model Context Protocol.
This is defensive/offensive research for legitimate purposes. Test only systems you are explicitly authorized to assess, an in scope bug bounty program or a contracted engagement.