fix(server): bind to loopback and reject cross-origin writes - #5
Merged
Conversation
The server passed no host to listen(), so it bound the wildcard interface and every /api route — the diff, the repository's files, the review comments — was readable by anything routable to the machine. It also sent Access-Control-Allow-Origin: * on every response, so any page open in the same browser could read a private diff, and could POST to /api/revert-file, /api/revert-hunk, /api/threads and /api/github/push-comments without a preflight. DIFFITY_BIND selects the interface and defaults to 127.0.0.1, with a warning when it is widened. DIFFITY_HOST keeps its existing meaning: the hostname in the printed URL only. The UI is served from the same origin and calls /api with relative paths, so it needs no CORS headers at all. Writes now additionally require Sec-Fetch-Site: same-origin (or an absent/loopback Origin), which a cross-site page cannot forge. Navigations are GET and unaffected. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_018PkYQzbsnMihHesafWvXKs
This was referenced Aug 21, 2026
fiddur
marked this pull request as ready for review
August 21, 2026 13:34
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
First of the security fixes.
server.listen(currentPort)passed no host, so the server bound thewildcard interface — every
/apiroute, meaning the diff, the repository's files and the reviewcomments, was readable by anything routable to the machine, with no authentication.
DIFFITY_HOSTdoes not help: it only changes the hostname in the printed URL.
Every response also carried
Access-Control-Allow-Origin: *, which authorises any page open in thesame browser to read a private diff, and a cross-origin
POSTwithContent-Type: text/plainis aCORS simple request, so
/api/revert-file,/api/revert-hunk,/api/threadsand/api/github/push-commentswere reachable without a preflight.DIFFITY_BINDselects the interface, default127.0.0.1, with a warning printed when widened/apiwith relative paths, so it never needed themSec-Fetch-Site: same-originor an absent/loopbackOrigin— unforgeable cross-site, and navigations are GET so they are unaffectedX-Content-Type-Options: nosniffon every responseVerified:
ss -ltnshows127.0.0.1:5391where it previously showed the wildcard; a cross-sitePOSTto/api/revert-filereturns 403; a same-originPOSTstill reaches its route; noAccess-Control-*header is sent. 163 tests pass.Still outstanding from the audit, in follow-ups: shell interpolation in the git helpers (a PR
containing a filename with
$(…)executes on open), percent-encoded path traversal in/api/tree/raw/, andrehype-rawwithout a sanitizer.Stacked on #4.
🤖 Generated with Claude Code
https://claude.ai/code/session_018PkYQzbsnMihHesafWvXKs