A new HTTP method just shipped that GET and POST have needed for 25 years.
1. What is it
QUERY is a new HTTP request method, sibling to GET and POST, defined to carry a request body on a method that is still classified as safe and idempotent under RFC 9110 semantics — the same safety class as GET. A request looks like a POST, wire-format-wise (method + body + Content-Type), but a client, cache, or proxy is entitled to treat it like a GET: no state change implied, safe to retry, and cacheable.
It grew out of the WebDAV precedent (PROPFIND, REPORT, and RFC 5323’s SEARCH all did “safe method with body” back in 2003), but those are coupled to WebDAV/XML semantics. QUERY generalises the pattern for ordinary HTTP APIs, and was named for the URI “query” relationship rather than reusing SEARCH.
2. The gap it closes
Before QUERY, every API with a non-trivial filter/search/report shape had to pick a lesser evil:
MethodBodySafe / IdempotentCacheablePractical limitGETNo (by convention)YesYesURI length caps (~2–8 KB in practice); everything lands in logs and browser historyPOSTYesNoNo, by defaultSemantically “this changes state” even when it doesn’t — breaks caches, retries, and idempotency assumptionsQUERYYesYesYesNew method — support is not yet universal.
Concretely: search endpoints, report/analytics queries, filtered listings, and document-store lookups that need structured criteria (JSON filter trees, GraphQL-style query documents) no longer have to smuggle that structure into a query string or misuse POST to get it into a body.
3. How it works
Content-Typeis mandatory on the request — a server must reject a QUERY with missing or inconsistent media-type metadata.- Responses are cacheable, but the cache key must incorporate the request body (plus relevant metadata like encoding). A cache may normalise insignificant differences — e.g. a
+jsonSuffix — for key generation only, never for what’s actually sent to the origin. - A 2xx response may carry
Content-Location, pointing at a resource that represents the query result and can be re-fetched later with a plain GET. The RFC explicitly says that a URI should not embed sensitive parts of the query if the query itself carries sensitive data.
Status | Meaning
400 | Missing or inconsistent Content-Type415 | Unsupported media type for the query body
422 | Syntactically valid body, semantically invalid query
406 | Server can’t produce an acceptable response representation

4. Map of the RFC
A quick visual overview of how the RFC’s sections relate — safety/idempotency semantics, caching rules, and the security considerations feed off the same core definition

5. Client & server support
RFC 10008 was published in June 2026 — it is weeks old at the time of writing. No caniuse.com, Chrome Platform Status, or MDN compatibility entry for a QUERY-specific feature exists yet, and no browser has announced native handling.
Practically true today:
fetch()andXMLHttpRequestalready accept arbitrary method strings, sofetch(url, {method:'QUERY', body: ...})will send a QUERY request in every current browser — the gap isn’t the client API, it’s everything downstream: your server framework, reverse proxy, CDN, and WAF, most of which allowlist methods and will 405 or silently rewrite an unrecognized one.
Two things to verify per hop before you depend on QUERY in production, because they don’t come free with “the browser can send it”:
- CORS. QUERY is not on the CORS-safelisted method list (GET, HEAD, POST only). A cross-origin QUERY always triggers a
OPTIONSpreflight — different from a classic POST form submit, and it changes your CSRF threat model. - Everything between the browser and the origin. Load balancers, API gateways, WAF rule sets, and older reverse-proxy configs frequently hard-code the method allowlist to
GET, HEAD, POST, PUT, DELETE, OPTIONS. QUERY needs to be added explicitly almost everywhere in the chain.
6. If it isn’t supported
The RFC doesn’t mandate a fallback mechanism, so treat this as standard HTTP capability-negotiation practice, not spec text:
- Probe; don’t assume. Send
OPTIONSto the target and check whetherQUERYappears in theAllowresponse header before using it on the hot path. - Degrade to POST-with-override. If QUERY isn’t in
Allow, or the QUERY request itself comes back405/501, fall back to a POST carrying the same body plus a marker header (e.g.X-HTTP-Method-Override: QUERY) so the origin can still special-case it if it wants to. - Cache accordingly. If you fall back to POST, remember POST responses aren’t cached by default — you lose the caching benefit that was half the point of using QUERY, so budget for that in the fallback path rather than being surprised by it.
async function query(url, body) {
const probe = await fetch(url, { method: 'OPTIONS' });
const allowed = (probe.headers.get('allow') || '').includes('QUERY');
return fetch(url, {
method: allowed ? 'QUERY' : 'POST',
headers: {
'Content-Type': 'application/json',
...(!allowed && { 'X-HTTP-Method-Override': 'QUERY' })
},
body: JSON.stringify(body)
});
}
7. Security considerations
Stated in the RFC
- Logging exposure, improved. Moving query criteria from the URI into the body means it stops landing in server access logs, browser history, and proxy logs by default — a genuine improvement over GET-with-querystring for sensitive filter criteria.
- Result-URI leakage. If a server mints a
Content-LocationURI for the query result, that URI must not embed sensitive request content — otherwise you’ve just moved the leak from the request log to the response header / cache key. - Cache-key/normalization mismatch. Because the cache key must reflect the body, any normalization the cache applies that diverges from what the origin actually does creates a false-positive match — one client’s cached response served to another client with a materially different query. This is a cache-poisoning-shaped risk, not a hypothetical one.
- Not CORS-safelisted. QUERY forces a preflight cross-origin. Don’t assume “it’s basically GET” extends to authorization — treat it exactly like POST for CSRF-token and same-origin checks.
Reasonable inferred risks (not RFC text — engineering judgment)
⚠️ Not stated in RFC 10008 — analogous to known POST-body risks:
- Query-language injection. A QUERY body is, definitionally, a structured query — SQL-, NoSQL-, or GraphQL-shaped payloads are exactly what it’s designed to carry. Treat the body with the same injection scrutiny you’d give any query-builder input; “it’s a safe method” says nothing about what the server does with the body’s contents.
- Method-allowlist / WAF bypass. Security controls tuned for GET/POST behavior (rate limits, WAF signatures, request-size caps) may not yet have QUERY-specific rules, creating a gap an attacker can probe for simply by resending a blocked POST payload as QUERY.
- Idempotency-assumption abuse. Because QUERY is trusted as safe/idempotent by intermediaries, a server that quietly performs a side effect on QUERY breaks every downstream assumption (safe retries, prefetching, crawler behavior) — a self-inflicted risk if implementers use QUERY for anything beyond retrieval.
8. Testing QUERY
No QUERY-specific handling has shipped yet in Burp Suite, ZAP, or nuclei as of this writing — PortSwigger’s method-testing docs are still generic. Test manually via Repeater / raw sockets rather than assuming built-in coverage.
- [ ] Method allowlist enumeration. Confirm every hop (CDN, WAF, gateway, app server) explicitly allows QUERY rather than passing it through unfiltered or silently coercing it to GET/POST.
- [ ] Content-Type enforcement. Send QUERY with missing, mismatched, and malformed
Content-Type— confirm 400/415, not a body-sniffing fallback that skips validation. - [ ] Cache-key correctness. Send two QUERY requests with different bodies but normalization-adjacent headers (charset, encoding, media-type suffix); confirm the cache never serves one client’s result for another’s query — this is your Param-Miner-style cache-poisoning check, adapted for a body-keyed cache.
- [ ] CORS preflight behavior. Verify cross-origin QUERY actually triggers
OPTIONSand that the server’sAccess-Control-Allow-Methodsdoesn’t blanket-allow QUERY from any origin without the same auth checks applied to POST. - [ ] Injection fuzzing on the body. Run standard SQL/NoSQL/GraphQL injection payload sets against the QUERY body exactly as you would a POST-based search endpoint — QUERY changes transport semantics, not server-side trust.
- [ ] Side-effect check. Confirm QUERY endpoints genuinely have no observable state change (safe) and return identical results on repeat (idempotent). A QUERY endpoint that fails either is mis-implemented and breaks caller assumptions, including caches and crawlers upstream.
- [ ] Filter/allowlist bypass probing. Retry payloads previously blocked on POST/GET as QUERY to check whether WAF signatures and rate limits were ported to the new method.
- [ ] Content-Location leakage. If the response sets
Content-Location, inspect it for embedded sensitive query content, and check whether that derived resource enforces the same authorization as the original QUERY.
Browser/runtime support facts above are stated conservatively: as of this writing, no primary source (caniuse, Chrome Platform Status, MDN) documents native QUERY support, and the RFC is roughly one month old. Re-verify before citing specific version numbers.
Sources: datatracker.ietf.org/doc/rfc10008 · rfc-editor.org/rfc/rfc10008 · draft-ietf-httpbis-safe-method-w-body · PortSwigger — supported HTTP methods
This article was first published on Medium.
