feat(config): reject over-broad Origin allowlist entries (#23)#36
Merged
Conversation
The edge request guard (internal/edge/guard.go) is a pure matcher: an
allowed_origins entry matches exactly, or — when it ends in "*" — by the
prefix before the "*". It faithfully honors whatever it is given, so it
cannot tell an intentional scope (vscode-webview://*) from operator
misconfiguration that defeats the rebinding guard (a bare "*" matches every
Origin; "http://*" matches any http origin).
Put that judgement at the fail-fast config gate, where the gateway already
rejects bad configuration (§7), keeping the guard a pure matcher. Validate
rejects, with an actionable message:
- a bare "*" (allow-all);
- a wildcard not preceded by a scheme delimiter ("localhost*", "://*");
- a wildcard over the whole host of a network scheme ("http://*",
"https://*", "ws://*", "wss://*"), while opaque schemes keep the scheme
as the boundary ("vscode-webview://*", "app://*") and still load;
- an exact entry that is not a bare origin (no scheme, or carrying a path,
query, or fragment — a real Origin header carries none, so it is dead
config).
The check lives in Validate(), so it guards both initial load and SIGHUP
reload. Legitimate forms (http://localhost, vscode-webview://*) are covered
by a positive test.
Closes #23
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
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.
What
Validate
allowed_originsat the fail-fast config gate and reject entries that defeat the edge's DNS-rebinding guard (design §8, issue #23).The guard (
internal/edge/guard.go) is a pure prefix/exact matcher — it faithfully honors whatever it is given and cannot judge whether an entry is too broad. That judgement belongs in the validation layer, where the gateway already rejects bad configuration before request time (§7). This keeps the guard a pure matcher.Config.Validatenow rejects, with an actionable message:"*"(empty prefix → matches every Origin, allow-all);"localhost*","://*");"http://*","https://*","ws://*","wss://*"). Opaque schemes keep the scheme itself as the boundary ("vscode-webview://*","app://*") and still load;Originheader carries none, so such an entry is dead config that never matches).The check is part of
Validate(), so it guards both initial load (config.Load) and SIGHUP reload (app.go).Acceptance criteria (issue #23)
http://localhost,vscode-webview://*) still load.Testing
TestValidateRejectsfor every rejected form; newTestValidateAcceptsLegitimateOriginsfor the allowed forms.make verifylocally: build, vet,-racetests, coverage 95.3% (gate 80%),golangci-lintv2.12.2 clean, gofmt clean.config/portcullis.example.yaml) still validates (existing app test).Closes #23
🤖 Generated with Claude Code