🔗Security
A dedicated security audit was performed (audit/REPORT.md); its high-priority findings are fixed and locked in by regression tests in tests/test_security.nim. This page summarizes the hardening already in place.
🔗Hardened by default
- Idle / read timeouts —
readTimeoutMsandkeepAliveMsare enforced per connection, closing slowloris and idle keep-alive connections that never complete their requests. - Bounded header buffering — an oversized header packet is rejected (
414/431) before the parser grows its buffer to the packet size, so a hostile multi-megabyte header block cannot force a matching allocation. - Overflow-safe
Content-Length— adversarial values (e.g.2^63) are rejected instead of crashing or wrapping to a negative length, closing a request-smuggling/desync primitive. - Bounded streaming uploads — streamed bodies (temp-file and multipart) are capped even with
maxBodySize = 0, and size-limit violations reply413instead of raising an unhandled exception. - WebSocket frame caps — an absolute frame-size cap applies even in
maxFrameSize = 0("unlimited") mode, preventing OOM on hostile 64-bit lengths and unbounded fragmented-message assembly. - Stack-safe response headers —
sendFile/streamFileheader assembly grows safely; long filenames or custom headers can no longer overflow a fixed stack buffer. - Path-confusion-proof static serving —
serveFilerequires a real path boundary underfsRoot, so a sibling directory sharing the prefix (e.g./var/www2) can no longer be served. - Symlink-safe static serving — served paths are resolved with
realpathand must stay underfsRoot; a symlink inside the root pointing outside is rejected with403. - Multipart per-file limits —
server.maxFileSizebounds a single uploaded part independently of the total body cap (violations reply413). - WebSocket handshake hardening —
handshakeTimeoutMscloses connections that never complete the HTTP→WebSocket upgrade, andmaxHandshakeSessionscaps in-flight handshakes (handshake-stall DoS defense). - Strict header parsing — obs-fold / leading-whitespace header lines are rejected (
400), andTransfer-Encodingenables chunked framing only when the final token is exactlychunked. - Thread-safe rate limiter —
RateLimiterguards its bucket table with a lock, so it can be shared across multi-threaded server workers. - TLS reflection guards — the TLS
sendvcoalesce buffer is capped (1 MB), so an attacker-controlled response echoed over TLS cannot force an arbitrarily large allocation.
🔗Recommended production configuration
For publicly reachable endpoints, set explicit caps instead of relying on the defaults (the maxBodySize = 0 backstop is MaxStreamBodySize):
let server = newHttpServer(loop)
server.maxBodySize = 50 * 1024 * 1024 # 50 MB total request body
server.maxStreamBodySize = 64 * 1024 * 1024 # hard cap even when maxBodySize=0
server.maxFileSize = 10 * 1024 * 1024 # 10 MB per uploaded file
server.maxFieldSize = 64 * 1024 # 64 KB per text field
server.maxConnections = 4096 # cap concurrent connections
server.maxPipelineDepth = 4 # cap pipelined requests
server.readTimeoutMs = 5_000 # slowloris / partial-request close
server.setKeepAliveTimeout(5_000) # idle keep-alive closeThe same caps apply to the standalone WsServer via maxFrameSize, handshakeTimeoutMs, maxHandshakeSessions, and (once enabled) a post-upgrade idleTimeoutMs.
🔗Smuggler
Smuggler is a grammar-based HTTP/1.x request-smuggling fuzzer built for this library: it generates and mutates requests from a context-free grammar, detects CL/TE desyncs with an in-process oracle, and drives live servers with the two-request response-pairing technique.
nimble testSmuggler # in-process + differential suites
smuggler -g tests/fuzz/request-line.cfg -t 127.0.0.1:9000 -n 1000🔗Security roadmap
- Coverage-guided fuzzing of the HTTP / WebSocket / multipart parsers (libFuzzer & nim-drchaos adapters in
smuggler) - ASan/UBSan sanitizer build wired into CI
- Stream body bytes before first-packet buffering (avoid peak RAM on large single-packet uploads)
- Multipart per-file size limits wired to server configuration
- Symlink-safe static serving (realpath checks)
- WebSocket handshake timeout and handshake-session bound
- Rate-limiter thread-safety in multi-threaded mode
- Strict header parsing (reject obs-fold/leading-whitespace header lines, non-
chunkedTransfer-Encodingtokens) - Response-reflection guards for large attacker-controlled echoes under TLS
🔗Related docs
- Testing — how the hardening is verified
- Static files — path/symlink safety details
- Multipart — upload caps
- WebSocket — frame/handshake caps