Security and Hardening
Wisp is young and has not been audited, and it can be broken. This page lists what is done, how it is tested, and what was found and fixed, so you can judge for yourself. Defaults and the CSP are in CLI, dev loop and security, limits in Runtime and build.
Status: Young, Actively Hardened
- More than 1,000 tests run on every change: the runtime, the compiler, the CLI, the edge bridges and an app that uses every feature, plus a test that compiles every code sample of the reference.
- Parsers are fuzzed with a seeded generator that breaks inputs the way hostile clients do: the HTTP/1 parser, HTTP/2 frames and HPACK, JSON, forms, cookies, WebSocket frames and the signing code. The compiler's template and Rust scanners are fuzzed with malformed, deeply nested and huge input, and
wisp fmtwith a round trip that must be idempotent and keep every visible character. A failing seed repeats. - A table of request-smuggling shapes (conflicting lengths, doubled
Transfer-Encoding, bad chunking) must each be refused. - Every fast path is proven at startup and falls back, and nothing after startup panics. No
unsafeoutside the Linux I/O drivers and the edge exports. - Each pass hunts for bugs in one area (HTTP, the app and browser script, the build, the CLI, the edge bridges) and each finding gets a test. The list below is what the latest passes changed.
What the Latest Passes Hardened
Servers
- HTTP/2: a reset a client makes us send (the MadeYouReset shape) spends the same reset budget as one it sends. Past 1 MiB of incoming bodies only the oldest stream's window reopens. A peer sending past the receive window gets FLOW_CONTROL_ERROR.
content-lengthis digits only, and repeats must agree. - A streamed answer still hears its client leave after 64 KB were sent behind it, so the connection and its
WISP_MAX_CONNSslot are freed. WISP_CLIENT_IP_HEADERtakes the last address of the header's last line, which the trusted proxy added; a client can forge the first.Error::redirectwith a CR or LF in the location is a logged 500, and a non-3xx status is logged and sent as 303. Neither panics or splits a header.- A dev 5xx page never shows in a release build, even with
WISP_DEV=on. Stop signals are caught before thelisteningline.
Files and uploads
- Upload file names lose a drive (
C:) and an NTFS stream (:stream), as well as paths. - Static files and
Response::file_inanswer 404 for Windows device names (nul,CON.txt,COM1) and for names Windows trims (a.txt.,a.txt).
Browser script and dev mode
- The template-swap and the other dev endpoints answer only a loopback
Host(against DNS rebinding), and the swap also needs thex-wisp-devheader, so another site cannot rewrite your templates. wisp.jsleaves cross-origin form posts to the browser. A form field named__wispEnhancecannot replaceuse:enhance. Thejavascript:scheme guard on URL attributes is fuzzed with random URLs.
Build and CLI
- A route file name that is not UTF-8 or has a control character is an error, not text injected into generated comments.
wisp fmtno longer panics on a tag cut off after an attribute name. wisp service installquotesExecStart, escapes the plist XML, and refuses an app folder with a quote,%or a control character in its path, which could add unit directives.wisp mcpcaps a message line at 16 MiB instead of buffering without bound.
Edge hosts
- Raw connections on Node, Bun and Deno have the native head and body deadlines: a trickled request is refused 408 when its next bytes come.
- The bridges that read a body with the host's
fetchstop one byte past the route's limit and the app answers 413, so an endless body is not held in memory. - A WebSocket message past the limit closes with 1009, and 4009 on Deno, whose
closeaccepts no 1009. - Windows hosts pass environment names to the app upper-cased, so reading
PATHworks.
Not Claimed
- No audit, no bug bounty and no certification. A TLS server is not built in: put a proxy in front for browsers, as Deploying says.
- Fuzzing and tests find what they are written to find. The fuzz targets are in the repository: read them.
- A debug build is for your machine: behind a proxy on the same machine every peer is loopback, so never serve one.
Found something? Open an issue on GitHub, and a failing request or file is the best report.
Is This Page Useful?