☠ badtests — malicious HTTP response server

Each endpoint returns a deliberately malformed HTTP response to test client resilience.
Click any endpoint to hit it directly.

📋 /logs — View all visitor IPs, user agents, headers, and timestamps
Table of Contents

Content-Length Abuses

/cl-word — Content-Length: banana

Content-Length set to a word. Python accepts it, curl rejects.

/cl-empty — Content-Length: (empty)

Empty Content-Length header. Python accepts, curl rejects.

/cl-negative — Content-Length: -99999999999999999

Massive negative Content-Length. Python accepts, curl rejects.

/cl-huge — Content-Length: 99999999999999999

Claims ~100 petabytes. Both accept. curl reports remaining bytes.

/cl-zero — Content-Length: 0 (body sent)

CL is 0 but server sends "surprise!". Both read 0 bytes. Wire shows body was sent.

/cl-float — Content-Length: 3.14159

Float CL. curl truncates to 3 (returns "hel"). Python ignores it, returns all 5 bytes.

/cl-hex — Content-Length: 0xDEAD

Hex CL. curl treats as 0 (empty body). Python ignores it, returns all 5 bytes.

/cl-null — Content-Length: 5\x00

Null byte after digit. curl rejects (Nul byte in header). Python accepts silently.

/cl-negative-one — Content-Length: -1

Simple negative CL. curl rejects, Python accepts.

/cl-nan — Content-Length: NaN

NaN as CL. curl rejects, Python accepts.

/cl-inf — Content-Length: Infinity

Infinity as CL. curl rejects, Python accepts.

/cl-mismatch — Content-Length: 1 (body is 30 bytes)

CL says 1, body is 30 bytes. Both read exactly 1 byte. Extra data poisons keep-alive.

Content-Type Abuses

/ct-garbage — Content-Type: 200 random chars

Random printable chars with \n \r \t. Accidental CRLF injection. Different every time.

/ct-multi — Content-Type: 5 MIME types

Comma-separated MIME types. Both accept. RFC says only one allowed.

/ct-empty — Content-Type: (empty)

Empty Content-Type. Both accept without complaint.

/ct-null — Content-Type: text/\x00html

Null byte in MIME type. curl rejects, Python accepts with null present.

/ct-emoji — Content-Type: 💀/🔥

Emoji MIME type. Both accept. Violates HTTP/1.1 ASCII requirement.

/ct-mega — Content-Type: 10KB long

10,000 A characters. Both accept. No header length limit enforced.

/ct-crlf — Content-Type with CRLF injectionCRITICAL

🚨 CRITICAL: Injects X-Injected: true header via CRLF in Content-Type value. Works on BOTH.

/ct-semicolon — Content-Type with 50 charset params

50 repeated ;charset=utf-8 params. Both accept. Parser could waste cycles.

Status Code Abuses

/status-neg — Status: -1

Negative status code. Both reject.

/status-zero — Status: 0

Zero status code. Both reject.

/status-999 — Status: 999

Out-of-range 3-digit status. Both accept. RFC defines 100-599 only.

/status-huge — Status: 99999

5-digit status code. Both reject.

/status-word — Status: BANANA

Non-numeric status. Both reject.

Header Abuses

/hdr-mega-name — Header name: 64KB of As

curl accepts (no limit). Python rejects (LineTooLong >65536 bytes).

/hdr-mega-val — Header value: 1MB of Bs

Both reject. Python hits 64KB line limit. curl chokes on 1MB buffer.

/hdr-1000 — 1000 headers

curl accepts all 1000. Python rejects (>100 headers).

/hdr-empty-name — Header: : empty_name

Empty header name. Both accept. Violates RFC 7230.

/hdr-no-colon — Header without colon

curl rejects. Python silently drops the malformed line and continues.

/hdr-dup-cl — Duplicate Content-Length: 5 and 999CRITICAL

🚨 CRITICAL: Smuggling vector. curl uses second CL (999). Python sees both.

/hdr-null — Header with null bytes

curl rejects (Nul byte in header). Python accepts, drops the null header.

/hdr-newline — Header with bare \n

curl rejects (Header without colon). Python treats as line folding.

Body Abuses

/body-endless — Infinite body streamWARNING

⚠️ WARNING: Streams 1KB/sec forever. Use --max-time. Neither client protects against this.

/body-none — Content-Length: 5, no body

Promises 5 bytes, sends 0. curl reports transfer closed. Python returns empty, no error.

/body-binary — 4KB binary as text/html

Random binary with text/html Content-Type. Both accept. No content validation.

Transfer-Encoding Abuses

/te-invalid — Transfer-Encoding: banana

Unknown TE. Both accept and ignore it. RFC says this should be an error.

/te-double — Content-Length + Transfer-EncodingCRITICAL

🚨 CRITICAL: Smuggling vector. curl prefers CL, Python prefers TE. Clients disagree.

/te-bad-chunk — Chunked with ZZZ chunk size

Invalid hex in chunk size. Both correctly reject.

Protocol Abuses

/proto-garbage — 512 random bytes (no HTTP)

Pure garbage. Both reject.

/proto-empty — Empty response (0 bytes)

Server closes immediately. Both reject.

/proto-half — HTTP/9.9 version

Unknown HTTP version. Both reject.

/proto-no-headers — Status line + body, no headers

Zero headers. Both accept. Valid in HTTP/1.0 but violates HTTP/1.1.

/proto-just-newlines — Response is just \r\n\r\n\r\n

Only blank CRLF lines. Both reject.

Encoding Abuses

/enc-utf16 — Body is UTF-16, header says UTF-8

Mismatched encoding. Both accept raw bytes. Consuming app would decode garbage.

/enc-gzip-lie — Content-Encoding: gzip (plaintext body)

Claims gzip, sends plaintext. Both accept without decompressing by default.

Redirect Abuses

/redir-self — 301 → /redir-self (loop)

Infinite redirect loop. curl follows up to --max-redirs. Python http.client does not follow.

/redir-garbage — 301 → \x00\xff://💀:99999/../../etc/passwd

Garbage URL with null bytes, emoji, bad port, path traversal. curl rejects, Python accepts (SSRF risk).

/redir-chain — 302 → /redir-chain?n=N+1 (infinite unique chain)

Infinite redirect with unique URLs each hop. Defeats redirect loop detection. curl follows --max-redirs (default 50).

Timing Abuses

/slow-headers — Slowloris: 1 byte per 0.5s headersWARNING

⚠️ WARNING: Hangs until timeout. Classic slowloris attack.

/slow-body — Body: 1 byte per second (a-z)WARNING

⚠️ WARNING: Takes 26 seconds without timeout.

HTML/Content Abuses

/html-utf16 — Full HTML page encoded as UTF-16LE

Title and body encoded as UTF-16LE but served as text/html with no charset. Browser/parser gets mojibake.

/html-long-title — HTML title is 1000 characters

Absurdly long <title> tag (1000 A chars). Tests tab/title bar handling in browsers and parsers.

/html-multiline-title — HTML title with embedded newlines

Title contains literal \n characters. Some parsers collapse whitespace, others preserve. Tab bars get weird.

/html-irc-title — Title with \r\nQUIT :reason injectionCRITICAL

🚨 CRITICAL: IRC protocol injection via HTML title. If an IRC bot fetches and relays this title, the QUIT/PRIVMSG could be injected into the IRC stream.

/html-unicode — Random unicode (U+1000 to U+3000) title and body

Title and body filled with random Myanmar, Ethiopic, Devanagari, CJK chars. Different every request.

/html-meta-refresh — Meta refresh loop (0 second)WARNING

⚠️ WARNING: Page reloads itself every 0 seconds via meta tag. Infinite reload loop. Browser tab goes crazy.

Terminal Abuses

/ansi-chaos — ANSI escape code nightmareWARNING

⚠️ WARNING: Clears screen, hides cursor, changes window title, blink text, random cursor positioning. Will wreck your terminal.

JavaScript Browser Abuses

/js-alert — Infinite alert() loopWARNING

⚠️ WARNING: Opens alert dialogs in an infinite loop. Browser tab becomes unresponsive. Must force-kill tab.

/js-history — History flood (50,000 entries)WARNING

⚠️ WARNING: Pushes 50,000 entries to browser history. Back button becomes useless. Browser may lag.

/js-download — Download bomb (200 files)WARNING

⚠️ WARNING: Triggers 200 simultaneous file downloads via Blob URLs. Browser download manager explodes.

/js-clipboard — Clipboard hijackCRITICAL

🚨 CRITICAL: Silently replaces clipboard content with a malicious shell command every 100ms. Paste at your own risk.

/js-forkbomb — JavaScript fork bombWARNING

⚠️ WARNING: Spawns infinite Web Workers and recursive iframes. CPU/RAM will spike. Browser may crash.

/js-webgl — WebGL GPU killerWARNING

⚠️ WARNING: Runs an extremely heavy fragment shader in a tight render loop. GPU usage spikes to 100%. May freeze display.

/js-audio — Audio oscillator hellWARNING

⚠️ WARNING: Creates 20 oscillators at random frequencies changing 10x per second at max volume. Extremely loud.

/js-popup — Popup storm (100 windows)WARNING

⚠️ WARNING: Attempts to open 100 popup windows at random positions. Most browsers block after the first.

/js-cookie — Cookie bomb (3000 cookies)CRITICAL

🚨 CRITICAL: Sets 3000 cookies. Future requests to this server include ~12MB of Cookie headers. May DoS the server.

/js-beforeunload — Unescapable page (beforeunload)WARNING

⚠️ WARNING: Traps you with a beforeunload dialog every time you try to leave. Also opens itself in new tabs.

/js-tabbomb — Tab bomb with audio + downloadsCRITICAL

🚨 CRITICAL: Rapidly opens new tabs in a loop. Each tab auto-plays random oscillator audio with visualizer and spams file downloads. Will overwhelm your browser.

/js-serviceworker — ServiceWorker hijackCRITICAL

🚨 CRITICAL: Registers a ServiceWorker that intercepts ALL future requests to this origin and injects content.

Image/File Abuses

/img-bait — Image bait-and-switch

Shows a green "SAFE" image on the page. Download link gives you a red "HACKED" image. Same server, different file.

/img-svg-xss — SVG with embedded JavaScriptCRITICAL

🚨 CRITICAL: Serves an SVG image with an embedded <script> tag. If rendered as image/svg+xml, JS executes. XSS via image file.

/img-polyglot — GIF/JS polyglot fileCRITICAL

🚨 CRITICAL: Valid GIF89a image that is also valid JavaScript. Can be loaded as both <img> and <script>.

Network Abuses

/net-gzip-bomb — Gzip bomb (~10KB → 10MB)WARNING

⚠️ WARNING: ~10KB gzip response that decompresses to 10MB of zeros. Clients with auto-decompress will allocate 10MB.

/net-event-flood — SSE event flood (infinite)WARNING

⚠️ WARNING: Server-Sent Events stream that fires events as fast as possible forever. EventSource will buffer infinitely.

/net-mime-sniff — MIME type confusion (JS as image/jpeg)CRITICAL

🚨 CRITICAL: Serves JavaScript code with Content-Type: image/jpeg. If browser MIME-sniffs, the JS executes. Tests X-Content-Type-Options enforcement.

/net-cache-poison — Contradicting cache headers

Every cache header contradicts every other: no-cache + max-age=999999, public + private, future Last-Modified, wildcard Vary.

/net-hsts-bomb — HSTS with insane max-ageCRITICAL

🚨 CRITICAL: Sets Strict-Transport-Security with max-age=999999999 and includeSubDomains. Browser will force HTTPS for 31 years.

Miscellaneous

/misc-ipv4 — Shows your connecting IPv4 address

Reflects the client IP from the TCP connection. Use -4 flag with curl to force IPv4.

/misc-ipv6 — Shows your connecting IPv6 address

Reflects the client IP. Server must be reachable over IPv6. Connect to [::1] for loopback IPv6.

Special Pages

/fingerprint — Browser fingerprinting demo

Collects and displays 25+ browser fingerprinting vectors: canvas, WebGL, fonts, timezone, CPU, memory, touch, audio, etc.