Quick overview of RFC 10008: The HTTP QUERY Method

HTTP Query method

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 (PROPFINDREPORT, 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-Type is 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 +json Suffix — 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-Type
415 | Unsupported media type for the query body
422 | Syntactically valid body, semantically invalid query
406 | Server can’t produce an acceptable response representation

Comparison table of HTTP methods GET, POST, and QUERY highlighting differences in request body, safety, idempotency, cacheability, CORS support, and practical limits.

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

A diagram illustrating RFC 10008 - HTTP QUERY Method, featuring key components such as definitions, solutions, mechanics, client support, fallback options, security considerations, and testing for method allowances.

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() and XMLHttpRequest already accept arbitrary method strings, so fetch(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 OPTIONS preflight — 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:

  1. Probe; don’t assume. Send OPTIONS to the target and check whether QUERY appears in the Allow response header before using it on the hot path.
  2. Degrade to POST-with-override. If QUERY isn’t in Allow, or the QUERY request itself comes back 405/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.
  3. 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-Location URI 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 OPTIONS and that the server’s Access-Control-Allow-Methods doesn’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.

Leave a Reply

Discover more from AlienCoders

Subscribe now to keep reading and get access to the full archive.

Continue reading