fix(browser): tighten strict browser hostname navigation#64367
Conversation
Greptile SummaryThis PR tightens browser SSRF protections in two ways: (1) hostname-based URLs are blocked in strict mode unless the hostname is an IP literal or explicitly operator-allowlisted (because Chromium's network stack re-resolves DNS independently from Node's SSRF checks), and (2) CDP HTTP discovery requests ( Confidence Score: 5/5Safe to merge — no P0/P1 issues found; previous release-ordering bug is resolved and the strict hostname gate is well-tested. All remaining findings are P2 (minor inline normalization vs shared helper). The two previously flagged blocking issues (release() ordering and the agent work-log file) are both resolved in this revision. Comprehensive regression tests cover the new strict-mode paths. No files require special attention. Reviews (2): Last reviewed commit: "fix(browser): address review follow-ups" | Re-trigger Greptile |
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: abbad83bc8
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
|
@codex review |
|
@greptile review |
|
Codex Review: Didn't find any major issues. Delightful! ℹ️ About Codex in GitHubCodex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
If Codex has suggestions, it will comment; otherwise it will react with 👍. When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback". |
7bf8540 to
bbe43b5
Compare
The PR's SelectionDeps uses getSsrFPolicy instead of the full state object; the state property was leftover from an earlier iteration.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 7e78000ad1
ℹ️ About Codex in GitHub
Codex has been enabled to automatically review pull requests in this repo. Reviews are triggered when you
- Open a pull request for review
- Mark a draft as ready
- Comment "@codex review".
If Codex has suggestions, it will comment; otherwise it will react with 👍.
When you sign up for Codex through ChatGPT, Codex can also answer questions or update the PR, like "@codex address that feedback".
| cdpUrl: profile.cdpUrl, | ||
| ssrfPolicy: state().resolved.ssrfPolicy, | ||
| }); | ||
| const pages = await listPagesViaPlaywright({ cdpUrl: profile.cdpUrl }); |
There was a problem hiding this comment.
Propagate SSRF policy to Playwright listTabs calls
This call now invokes listPagesViaPlaywright without ssrfPolicy, and the pre-check assertCdpEndpointAllowed was also removed in this function. In strict mode, that means connectBrowser receives undefined policy and skips endpoint SSRF validation on cache miss, so a blocked cdpUrl can still be connected and cached before any guard runs. This is a security regression for remote profiles that use persistent Playwright tab listing.
Useful? React with 👍 / 👎.
| await focusPageByTargetIdViaPlaywright({ | ||
| cdpUrl: profile.cdpUrl, | ||
| targetId: resolvedTargetId, | ||
| ssrfPolicy: state().resolved.ssrfPolicy, | ||
| }); |
There was a problem hiding this comment.
Propagate SSRF policy to Playwright focus/close calls
The Playwright focus/close path now omits ssrfPolicy when calling focusPageByTargetIdViaPlaywright (and similarly closePageByTargetIdViaPlaywright below), while endpoint pre-checks were removed from this file. Because Playwright session attachment enforces endpoint SSRF policy only when connectBrowser is called with a policy on cache miss, these operations can bypass strict cdpUrl blocking for remote profiles.
Useful? React with 👍 / 👎.
| await resolvePinnedHostnameWithPolicy(parsed.hostname, { | ||
| policy: ssrfPolicy, | ||
| }); |
There was a problem hiding this comment.
Rewrap endpoint SSRF failures as endpoint-scoped errors
Removing the SsrFBlockedError -> BrowserCdpEndpointBlockedError conversion here changes error classification for blocked CDP endpoints. toBrowserErrorResponse still treats raw SsrFBlockedError as a navigation-target failure, so strict-policy endpoint denials are now reported as navigation blocks instead of endpoint configuration blocks, which breaks the existing endpoint-vs-navigation error contract.
Useful? React with 👍 / 👎.
) * fix(browser): tighten strict browser hostname navigation * fix(browser): address review follow-ups * chore(changelog): add strict browser hostname navigation entry * fix(browser): remove stale state prop from SelectionDeps call site The PR's SelectionDeps uses getSsrFPolicy instead of the full state object; the state property was leftover from an earlier iteration. --------- Co-authored-by: Devin Robison <[email protected]>
) * fix(browser): tighten strict browser hostname navigation * fix(browser): address review follow-ups * chore(changelog): add strict browser hostname navigation entry * fix(browser): remove stale state prop from SelectionDeps call site The PR's SelectionDeps uses getSsrFPolicy instead of the full state object; the state property was leftover from an earlier iteration. --------- Co-authored-by: Devin Robison <[email protected]>
) * fix(browser): tighten strict browser hostname navigation * fix(browser): address review follow-ups * chore(changelog): add strict browser hostname navigation entry * fix(browser): remove stale state prop from SelectionDeps call site The PR's SelectionDeps uses getSsrFPolicy instead of the full state object; the state property was leftover from an earlier iteration. --------- Co-authored-by: Devin Robison <[email protected]>
) * fix(browser): tighten strict browser hostname navigation * fix(browser): address review follow-ups * chore(changelog): add strict browser hostname navigation entry * fix(browser): remove stale state prop from SelectionDeps call site The PR's SelectionDeps uses getSsrFPolicy instead of the full state object; the state property was leftover from an earlier iteration. --------- Co-authored-by: Devin Robison <[email protected]>
) * fix(browser): tighten strict browser hostname navigation * fix(browser): address review follow-ups * chore(changelog): add strict browser hostname navigation entry * fix(browser): remove stale state prop from SelectionDeps call site The PR's SelectionDeps uses getSsrFPolicy instead of the full state object; the state property was leftover from an earlier iteration. --------- Co-authored-by: Devin Robison <[email protected]>
Summary
Changes
/json/versionrequests throughfetchWithSsrFGuardwhen an SSRF policy is activeValidation
corepack pnpm test extensions/browser/src/browser/navigation-guard.test.ts extensions/browser/src/browser/cdp.test.ts extensions/browser/src/browser/pw-session.create-page.navigation-guard.test.tscorepack pnpm checkclaude -p "/review", but the command timed out without outputNotes