query-fuzzer
HTTP QUERY fuzzer
A compliance and vulnerability fuzzer for the HTTP QUERY method, as defined in
RFC 10008 – The HTTP QUERY Method.
QUERY is a safe and idempotent HTTP method that carries a request body
(like POST) but signals a read-only query operation (like GET). Because the
method is new, server implementations frequently mishandle its normative
requirements — Content-Type validation, status-code selection, caching-key
derivation, conditional requests — and inherit classic body-handling flaws such
as length/encoding mismatches, request smuggling, and injection through the
query body.
query_fuzzer.py is a single-file, standard-library-only tool. It speaks
HTTP/1.1 over a raw socket so it can emit deliberately malformed requests
that high-level clients (requests, httpx) would silently sanitise.
⚠️ Authorised use only. This tool sends malformed and potentially disruptive traffic. Only point it at systems you own or are explicitly permitted to test.
Requirements
- Python 3.9+ (developed and tested on 3.12). No third-party packages.
- A virtual environment is optional since the tool is stdlib-only:
bash python -m venv venv && source venv/bin/activate # optional
Usage
python query_fuzzer.py <url> [options]
Examples:
# Compliance + injection/parsing checks (safe, default rate-limited to 10 req/s)
python query_fuzzer.py https://api.example.com --path /search --media sql
# Include disruptive checks (smuggling, oversized & slow body) and save a report
python query_fuzzer.py https://api.example.com --path /search --aggressive --json report.json
# Self-signed test target, unthrottled, JSON output, multiple paths
python query_fuzzer.py https://10.0.0.5 --insecure --rate 0 \
--path /search --path /v1/query --json out.json
On Windows Git Bash, prefix with
MSYS_NO_PATHCONV=1so paths like/searchare not rewritten, or pass the path inside the URL.
Options
| Option | Description |
|---|---|
url |
Target base URL, e.g. https://host:443/search (required). |
--path PATH |
Path(s) to test; repeatable. Overrides the URL path. |
--media {sql,jsonpath,json,xpath,text} |
Query body media type (default sql). |
--aggressive |
Enable disruptive checks (smuggling, oversized body, slow body). |
--threads N |
Concurrent checks per target (default 1). |
--rate R |
Max requests/second; 0 = unlimited (default 10). |
--timeout S |
Socket timeout in seconds (default 10). |
--max-body N |
Body size for the oversized-body check, in bytes (default 1 MiB). |
--insecure |
Skip TLS certificate verification (self-signed targets). |
--header H:V |
Extra header sent on every request; repeatable (e.g. auth tokens). |
--json FILE |
Write a machine-readable JSON report. |
--no-color |
Disable ANSI colour output. |
--yes |
Skip the interactive authorisation prompt (for CI). |
--verbose |
Verbose progress output to stderr. |
Exit code: 0 when no VULN/FAIL findings, 1 when at least one is
present (CI-friendly), 2 if authorisation was not confirmed.
What it tests
Each check maps to an RFC 10008 requirement or a well-known body-handling flaw.
Findings are classified PASS / FAIL (non-compliance) / VULN
(security-relevant) / WARN (heuristic) / INFO / SKIP.
Compliance & injection (always run)
| ID | Check |
|---|---|
| C1 | OPTIONS discovery of Allow and Accept-Query. |
| C2 | A well-formed QUERY with a supported Content-Type succeeds. |
| C3 | Missing Content-Type is rejected (no content sniffing). |
| C4 | Unsupported media type yields 415 (ideally with Accept-Query). |
| C5 | Content-Type/body mismatch is not sniffed/processed. |
| C6 | Unsatisfiable Accept yields 406. |
| C7 | Well-formed-but-meaningless query yields 422, not a leaky 5xx. |
| C8 | Empty body is rejected (a QUERY must carry a body). |
| C9 | Method names are case-sensitive (query/Query must be rejected). |
| C10 | Safety heuristic: a mutation-shaped body should not be accepted blindly. |
| C11 | Conditional QUERY (If-None-Match) yields 304. |
| C12 | Cache key incorporates the request body (no cache-poisoning collision). |
| C13 | Redirect semantics reported (303→GET vs 301/302/307/308→QUERY). |
| C14 | CORS preflight for QUERY (a non-safelisted method). |
| I1 | CRLF / response-splitting injection in header values. |
| I2 | Duplicate / conflicting Content-Type headers (parser confusion). |
| I3 | Malformed Content-Type parameter injection. |
| I4 | Format-specific body injection probes (SQLi / XPath / JSONPath / NoSQL). |
| I5 | Null bytes and oversized header values. |
Aggressive (only with --aggressive)
| ID | Check |
|---|---|
| A1 | Over/under-declared Content-Length. |
| A2 | CL.TE request-smuggling desync probe. |
| A3 | Oversized body (probes request-size limits). |
| A4 | Negative / non-numeric / huge Content-Length. |
| A5 | Malformed chunked-encoding edge cases. |
| A6 | Bounded slow-body (Slowloris-style) read-timeout probe. |
Safety
- An interactive authorisation prompt runs before any traffic (
--yesto skip). - Requests are rate-limited by default (
--rate 10). - Aggressive resource tests are bounded: the oversized-body size is capped by
--max-body, and the slow-body probe is time-boxed to a few seconds. - Side-effect (safety/idempotency) and redirect checks are inherently heuristic
against a black-box server and are reported as
WARN/INFO, never as a high-confidenceVULN.
Notes
- The tool reads only the first ~64 KB of each response, enough for status, headers, and error signatures.
- Output is grouped by severity; pass
--jsonfor a structured report suitable for diffing across runs or feeding into other tooling.