Files
Charlie CheeverandClaude Opus 5.5 1ddc34d634 The Three and Godot comparison servers serve only files inside dist
Both decoded the request path before opening it. Godot's prefixed `dist`
and checked nothing, so /%2e%2e%2foutside.txt read the game directory and
more parent segments reached further. Three's startsWith(root) check
admitted a sibling with the same prefix (/%2e%2e%2fdist-private/...).
Neither checked a link inside dist that leads out, a malformed escape
threw out of the handler, and both bound Bun's default 0.0.0.0 while
printing a loopback URL.

Each now decodes the path (a malformed escape is 400), takes the real
path of dist and of the file, and serves the file only when its real
path lies under dist's (base + separator) and it is a regular file; any
other answer is 404. Both bind 127.0.0.1, which every smoke script and
README already uses. The trial evidence's source hashes record what was
delivered then and are unchanged.

A probe that loads copies of both servers with Bun.serve stubbed (no
socket) and synthetic files: before, Three served the prefix sibling and
an escaping link, Godot all three escapes and the link, and both threw
on a malformed escape; after, every escape and the link are 404, the
malformed escape 400, and / and a file inside dist still 200.

Closes issues/closed/20261112-review-experiment-servers-escape-public-root.md.

Co-Authored-By: Claude Opus 5.5 <[email protected]>
2026-11-12 22:55:32 -08:00
..