Skip to content
This repository was archived by the owner on Aug 6, 2026. It is now read-only.

feat(browser): in-app browser tab with webview security hardening - #3181

Closed
MattPua wants to merge 18 commits into
mainfrom
posthog-code/browser-tab
Closed

feat(browser): in-app browser tab with webview security hardening#3181
MattPua wants to merge 18 commits into
mainfrom
posthog-code/browser-tab

Conversation

@MattPua

@MattPua MattPua commented Jul 6, 2026

Copy link
Copy Markdown
Member

Problem

Working on web changes means bouncing between the app and an external browser. There is no way to view docs, a local dev server, or another page inside the app next to a task.

Changes

CleanShot.2026-07-06.at.13.12.17.mp4

Adds an embedded browser tab, gated behind posthog-code-browser-tab and enabled by default in local development.

  • Adds a host-injected browser capability so unsupported hosts never mount Electron's <webview>.
  • Adds address, back, forward, reload, stop, loading, title, and persisted URL handling.
  • Normalizes public HTTP addresses to HTTPS while preserving HTTP for loopback development servers.
  • Keeps restored browser tabs visible with an unavailable state when the host or flag does not support them.
  • Waits for Electron dom-ready, surfaces attachment failures, and queues early Enter navigation until the webview is ready.
  • Adds a main-process feature gate synchronized with the renderer flag.
  • Hardens webview attachment preferences and uses a dedicated persisted partition.
  • Denies all guest permissions through an explicit empty allowlist.
  • Allows only HTTPS, loopback HTTP, or exactly about:blank for main-frame navigation.
  • Applies the same URL policy to popups and blocks unsafe programmatic requests, custom schemes, files, and metadata endpoints.

How did you test this?

  • Browser normalization, interaction, availability, permission, attachment, navigation, request, and feature-gate unit tests.
  • Desktop and UI typechecks, Biome, and host-boundary validation.
  • Packaged Electron E2E covering upgraded webview APIs, navigation, unsafe URL rejection, reload, and recovery.
  • Real development app over CDP, including immediate Enter navigation on a brand-new browser tab before dom-ready.

Automatic notifications

  • Publish to changelog?
  • Alert Sales and Marketing teams?

Created with PostHog Code

@trunk-io

trunk-io Bot commented Jul 6, 2026

Copy link
Copy Markdown

Merging to main in this repository is managed by Trunk.

  • To merge this pull request, check the box to the left or comment /trunk merge below.

After your PR is submitted to the merge queue, this comment will be automatically updated with its status. If the PR fails, failure details will also be posted here

@greptile-apps

greptile-apps Bot commented Jul 6, 2026

Copy link
Copy Markdown
Contributor

Comments Outside Diff (1)

  1. apps/code/src/main/window.ts, line 71-76 (link)

    P2 Session-level handlers reset on every webview attach

    guest.session is the shared persist:browser session, so setPermissionRequestHandler / setPermissionCheckHandler are overwritten each time a new browser tab is opened. The logic is idempotent here so the behaviour is correct today, but it is worth noting that calling setPermissionRequestHandler again replaces the previous handler rather than composing with it — if the handler ever diverges between webviews this will silently drop the earlier one.

    Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time!

Reviews (1): Last reviewed commit: "feat(browser): in-app browser tab with w..." | Re-trigger Greptile

Comment thread packages/core/src/panels/panelLayoutTransforms.test.ts
Comment thread packages/core/src/panels/panelLayoutTransforms.test.ts
- Globe button in panel tab bars opens an embedded browser tab
  (Electron <webview>), gated behind posthog-code-browser-tab flag
- Main-process hardening: preload/node stripped from guests, scheme
  allowlist (http/https/about), link-local metadata range blocked,
  powerful permissions denied, popups routed http(s)-only to OS browser
- Address bar normalizes input (scheme passthrough, host detection,
  search fallback); disallowed schemes become searches
- Last committed url persists on the tab for restore-on-reload

Generated-By: PostHog Code
Task-Id: 4bc7193a-bc2b-4365-8435-a6b20cd00c08
@MattPua
MattPua force-pushed the posthog-code/browser-tab branch from b4db740 to 7ca9a4e Compare July 6, 2026 15:01
@MattPua

MattPua commented Jul 6, 2026

Copy link
Copy Markdown
Member Author

Addressed the review feedback (PostHog Code, on behalf of the author):

  • Both P1 silent test bail-outs: explicit expect(...).toBe("leaf") assertions added before the type-narrowing guards
  • P2 (session handlers reset on every attach): permission handlers now install once per session via a WeakSet guard (hardenWebviewSession), so a future per-guest divergence can't silently replace an earlier handler
  • Rebased onto latest main — resolved conflicts with the new autoresearch tab type, conflicts are cleared

@github-actions

github-actions Bot commented Jul 6, 2026

Copy link
Copy Markdown

React Doctor found 11 issues in 4 files · 11 warnings.

11 warnings

src/features/browser/BrowserPanel.tsx

src/features/panels/components/TabBarButton.tsx

src/features/panels/components/TabbedPanel.tsx

src/renderer/platform-adapters/electron-browser-view.tsx

Reviewed by React Doctor for commit 78d5d91.

MattPua added 3 commits July 6, 2026 11:10
Single "+" opens a Terminal/Browser menu instead of a row of icon
buttons; falls back to the direct add-terminal button when the browser
flag is off (a one-item menu is worse than a plain button).

Generated-By: PostHog Code
Task-Id: 4bc7193a-bc2b-4365-8435-a6b20cd00c08
- Indeterminate top bar (shared quill-section-loading swoop) over the
  page area during loads
- Reload button becomes a stop button mid-load

Generated-By: PostHog Code
Task-Id: 4bc7193a-bc2b-4365-8435-a6b20cd00c08
Generated-By: PostHog Code
Task-Id: 4bc7193a-bc2b-4365-8435-a6b20cd00c08
@MattPua
MattPua force-pushed the posthog-code/browser-tab branch from 82f4907 to deae0e5 Compare July 6, 2026 17:10
Comment thread packages/ui/src/features/browser/BrowserPanel.tsx Outdated
Comment thread packages/ui/src/features/browser/BrowserPanel.tsx Outdated
Comment thread packages/ui/src/features/browser/BrowserPanel.tsx Outdated
Comment thread packages/ui/src/features/browser/BrowserPanel.tsx Outdated
Comment thread apps/code/src/main/window.ts Outdated
Comment thread apps/code/src/main/window.ts Outdated
Comment thread apps/code/src/main/window.ts Outdated
Comment thread apps/code/src/main/window.ts
MattPua added 4 commits July 6, 2026 16:11
Generated-By: PostHog Code
Task-Id: 29a0c450-6d5c-454e-a2c0-608d280d4737
Generated-By: PostHog Code
Task-Id: 29a0c450-6d5c-454e-a2c0-608d280d4737
Block the IPv6-mapped metadata address and GCP's metadata DNS name, which
the IPv4-only host check let through. Extract the pure navigation guard to
a testable module with regression coverage.

Generated-By: PostHog Code
Task-Id: 29a0c450-6d5c-454e-a2c0-608d280d4737
…elper

updateTabLabel/updateTabMetadata/updateBrowserTabUrl shared the same
find-tab-walk-and-map dance. Extract updateTabById; add coverage for the
two transforms that lacked it.

Generated-By: PostHog Code
Task-Id: 29a0c450-6d5c-454e-a2c0-608d280d4737
@MattPua
MattPua marked this pull request as ready for review July 6, 2026 20:38
@charlesvien charlesvien added the Stamphog This will request an autostamp by stamphog on small changes label Jul 10, 2026

@stamphog stamphog Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Security-sensitive Electron change (webviewTag enabled, navigation guards, permission handlers) with zero independent human review — all comments are from the PR author (self-review via AI) or a bot. Per policy, higher-risk changes need at least one independent human reviewer before auto-approval.

@stamphog stamphog Bot removed the Stamphog This will request an autostamp by stamphog on small changes label Jul 10, 2026
@charlesvien

Copy link
Copy Markdown
Member

Did we implement these already in #3221?

@MattPua

MattPua commented Jul 13, 2026

Copy link
Copy Markdown
Member Author

@charlesvien i believe those are "tab implementations" and this is actually running the browser

@adboio adboio self-assigned this Jul 17, 2026
adboio
adboio previously requested changes Jul 17, 2026

@adboio adboio left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(sry agent went rogue)

@adboio
adboio dismissed their stale review July 17, 2026 13:22

Posted in error; review feedback will be shared privately with the requester.

MattPua added 2 commits July 17, 2026 10:52
Generated-By: PostHog Code
Task-Id: b23f944d-dd7f-465b-9fed-1a1d028f35e1
Generated-By: PostHog Code
Task-Id: b23f944d-dd7f-465b-9fed-1a1d028f35e1
Comment thread apps/code/src/main/window.ts Outdated
@veria-ai

veria-ai Bot commented Jul 17, 2026

Copy link
Copy Markdown

PR overview

This pull request adds an in-app browser tab backed by a webview and introduces navigation-guard logic for controlling where the webview can load content from. The touched code focuses on handling browser navigation rules for local and web origins.

There is one open low-risk issue in the navigation guard: the loopback hostname check can incorrectly treat crafted remote DNS names as local loopback-style HTTP destinations. That could allow a webview to load plaintext remote content where HTTPS would normally be required, creating an opportunity for content tampering by an on-path attacker. One issue has already been addressed, so the remaining work is narrowed to tightening the loopback IPv4 validation.

Open issues (1)

Fixed/addressed: 1 · PR risk: 4/10

MattPua added 6 commits July 17, 2026 11:10
Generated-By: PostHog Code
Task-Id: b23f944d-dd7f-465b-9fed-1a1d028f35e1
Generated-By: PostHog Code
Task-Id: b23f944d-dd7f-465b-9fed-1a1d028f35e1
Generated-By: PostHog Code
Task-Id: b23f944d-dd7f-465b-9fed-1a1d028f35e1
Generated-By: PostHog Code
Task-Id: b23f944d-dd7f-465b-9fed-1a1d028f35e1
Generated-By: PostHog Code
Task-Id: b23f944d-dd7f-465b-9fed-1a1d028f35e1
Generated-By: PostHog Code
Task-Id: b23f944d-dd7f-465b-9fed-1a1d028f35e1
@MattPua
MattPua requested a review from adboio July 17, 2026 16:10
Generated-By: PostHog Code
Task-Id: b23f944d-dd7f-465b-9fed-1a1d028f35e1
// solely as the src a new blank browser tab mounts with before
// the user enters a url.
const LOOPBACK_HOSTS = new Set(["localhost", "0.0.0.0", "[::1]"]);
const LOOPBACK_IPV4 = /^127\./;

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Low: Loopback check accepts remote DNS names

A hostname such as 127.attacker.example matches this expression, so a page can redirect the guest to a remote plaintext HTTP origin that would otherwise require HTTPS. An on-path attacker can then replace the content loaded in the webview; require a complete canonical IPv4 literal instead.

Suggested change
const LOOPBACK_IPV4 = /^127\./;
const LOOPBACK_IPV4 = /^127(?:\.\d{1,3}){3}$/;

@github-actions

Copy link
Copy Markdown

This PR has had no activity for 7 days and has been marked stale. We are moving to the monorepo and tightening PR staleness in preparation, so it will be closed in 7 days if no further activity occurs.

@github-actions github-actions Bot added the stale No recent changes to PR label Jul 28, 2026
@charlesvien

Copy link
Copy Markdown
Member

Closing stale PRs ahead of Friday's monorepo migration. If this is a mistake, rebase and reopen for review.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Labels

stale No recent changes to PR

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants