Security

Hardening pass 1 — fuzzing and wire-level attacks (2026-10-09)

Development VM (Ubuntu 24.04, Linux 6.8), commit 4f5c52f.

Fuzzing (fuzz/, cargo +nightly fuzz run <target> -O)

Ten minutes per target, libFuzzer with AddressSanitizer, -max_len=8192, seeded with real inputs (WordPress .htaccess, benchmark configurations, PROXY v1/v2 lines, …).

TargetInputExecutionsCoverageCrashes
rangeRange header + file length260.9 M1830
request_hostHost / :authority270.8 M1300
proxy_protocolPROXY v1 / v2120.6 M1880
request_pathrequest path (+ invariants: no dot or empty segments)71.5 M3230
cgi_headCGI head from PHP15.8 M1 4410
forwarded_forX-Forwarded-For via trusted proxy12.5 M2620
cache_controlCache-Control4.8 M3410
configYAML configuration2.0 M14 5160
htaccess.htaccess0.6 M10 0810

HTTP/1 and HTTP/2 framing is hyper/h2’s (fuzzed upstream); it is covered below at the wire level instead.

Wire-level tests (tests/integration/tests/{smuggling,security}.rs)

  • 14 smuggling shapes — TE.CL, duplicate / obfuscated Transfer-Encoding (xchunked, space before colon, vertical tab, quoted, folded, upper case), TE on HTTP/1.0, Content-Length +5 / list / hex, NUL in a header, chunk-size overflow: at most one response, the connection closes, and the hidden request never reaches the upstream.
  • Pipelining: three requests in one write are answered in order, each upstream once.
  • Slowloris (headers), slow body, idle keep-alive, silent connections, and a client that stops reading (cut off by write_timeout).
  • HTTP/2 rapid reset (CVE-2023-44487): 2 000 open-and-cancel streams get GOAWAY and a close; other clients are still served.

Privilege separation (systemd units)

scalwsd.service had MemoryDenyWriteExecute=true. scalwsd starts Node.js and Python applications, which inherit it: Node.js aborted at start-up and PHP opcache.jit could not work. Removed (4f5c52f); every other restriction verified with Node.js.