feat(security): redirect re-validation + auth-header scoping via a shared Fetch interceptor#57
Merged
Merged
Conversation
…ared Fetch interceptor The URL policy was only checked once, before navigating, so a public URL that 302'd to an internal host (127.0.0.1, cloud metadata) was followed unchecked — redirect-SSRF (finding #4, HIGH). And auth middleware set Network.setExtraHTTPHeaders session-wide, leaking the Authorization header to every host including redirect targets (#9). Adds a single Page-level request interceptor (page_fetch.go) that owns CDP Fetch and multiplexes rules — first Block wins, header additions merge onto the continued request — so URL policy, resource blocking, and header injection share one Fetch session instead of fighting over Fetch.enable. Built on the off-read- loop dispatch from #53, so the continue/fail calls a handler makes don't deadlock. - Redirect guard: every Document request (initial nav + each redirect) is re-validated against the URL policy; installed by default when the validator blocks private IPs, skipped for trusted (AllowPrivateIPs) sessions. - Auth scoping: HeaderAuth now injects only for same-origin-as-navigation requests (tracked via Navigate), so the token isn't sent cross-origin or to a redirect destination. - BlockResources refactored onto the interceptor so it coexists with the guard. Tests: unit (origin/pattern/same-origin logic) + Chrome integration under -race proving a redirect is blocked at the Fetch layer, a no-op rule doesn't break navigation, and same-origin header injection works. Full integration suite green. Claude-Session: https://claude.ai/code/session_01QKTcmXFTKoTQr7mB3HCuHZ
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.
The last two security-review items, both requiring CDP request interception.
Problems
302'd to an internal host (127.0.0.1,169.254.169.254) was followed unchecked.HeaderAuthsetNetwork.setExtraHTTPHeaderssession-wide, sending theAuthorizationheader to every host the page contacted — including redirect destinations.Design: one shared interceptor
A single Page-level request interceptor (
page_fetch.go) owns CDPFetchand multiplexes rules: they're consulted in order, the first toBlockfails the request, and header additions from all rules merge onto the continued request. This lets URL policy, resource blocking, and header injection share one Fetch session — CDP allows only one interception owner, and each paused request must be resolved exactly once. It's built on the off-read-loop dispatch from #53, so the continue/fail calls a handler makes can't deadlock.Documentrequest (initial nav and each redirect) is re-validated against the URL policy. Installed by default when the validator blocks private IPs; skipped for trusted (AllowPrivateIPs) sessions.HeaderAuthnow injects only for requests same-origin with the navigation target (tracked inNavigate), so the token isn't sent cross-origin or to a redirect destination. Combined with the redirect guard, a token can't leak to an internal host.BlockResourcesrefactored onto the interceptor so it coexists with the guard (previously it calledFetch.enabledirectly — two owners would conflict).Tests
-race: a redirect is blocked at the Fetch layer (/blockednever fetched), a no-op rule doesn't break navigation (continue path), and same-origin header injection works.-race— no regression.Completes the scout deep-review batch (findings #4, #9).
https://claude.ai/code/session_01QKTcmXFTKoTQr7mB3HCuHZ