Repository navigation
Conversation
… allowlist The iframe proxy fronted any http:// upstream it was handed, stripping a remote site's framing headers and CSP and serving it from the shared loopback hostname, with nothing telling the user that a remote page had lost the protections its author relied on. And a frame load redirected off the grant's upstream origin was forwarded verbatim, so the webview's loopback-only frame-src refused it as a blank pane. The grant is the only chokepoint that matters: both webview CSPs admit only loopback frames, so a remote page reaches a pane only through a minted grant. So the proxy now classifies an upstream by the addresses the grant is pinned to (every one loopback, never the hostname) and refuses a non-local one as `external` unless the request says the user allowed its exact origin; a leased external grant is not reused once the allowance is withdrawn. Each host forwards only an exact `allowExternal: true`. The panel shows an "External website preview" warning with Open in browser, Allow this origin, and Cancel. Allowed origins persist per host install in localStorage, listed and removable in Settings -> General; allowing or removing one re-asks the host, so a removal closes an open preview. A frame load redirected to another origin is answered with a Dormouse page that posts `navigate` to the app, which takes it as a URL-bar entry through the same gate, replacing the redirecting history entry; a frame nested in a proxied page follows the redirect itself, outside the webview CSP. Cookies stay stripped and https:// stays refused; in-place following of off-proxy links and forms, and cookie support, stay under ## Future. Closes #572. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Exports ExternalPreviewPrompt so its layout and actions have a story: each action reaches its own handler, a host with no system browser drops Open in browser, and a long origin wraps in a narrow pane. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Ned asked for the gate to be an audited rule. security-local.md -> Browser panes gains a Guarantee row and FAIL IF S294 (claimed by the local domain's local-terminal stream, which already holds that heading); dor-browser.md's two bolded rules become the mechanism pointing at it. S294 skips S292 and S293, which the unmerged issue-1166-revoke-access-log takes; they sit in retired here only so the ledger lint passes on this branch alone, and come out of retired when the two branches meet. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Deploying mouseterm with
|
| Latest commit: |
0ec6a54
|
| Status: | ✅ Deploy successful! |
| Preview URL: | https://43180a6c.mouseterm.pages.dev |
| Branch Preview URL: | https://issue-572-iframe-local-first.mouseterm.pages.dev |
dormouse-bot
left a comment
Collaborator
There was a problem hiding this comment.
Dev servers on this machine whose URL isn't spelled as loopback will now hit the "External website preview" warning. Details inline.
…back Review on #1474: the gate called two kinds of upstream on this machine external. `python -m http.server` and other servers bound to every interface print http://0.0.0.0:<port>/, and listenerUrlsByPort names a server bound to one LAN, bridge, or tailnet interface by that interface's address. Both connect here, and both now opened behind the external-website warning. isLoopbackAddress becomes isThisMachineAddress: loopback, the unspecified 0.0.0.0 and ::, or an address one of this host's interfaces holds, read from os.networkInterfaces() at mint (injectable for tests), IPv4-mapped spellings counting as their IPv4. A private address on another host stays external. The spec's definition of local, S294, and the rationale name the new set. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve scripts/spec-word-budgets.json by taking the larger budget per spec. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Resolve scripts/security-rule-ids.json to next 295 with only 265 retired, since #1459 now uses S292 and S293 and this branch uses S294. Resolve scripts/spec-word-budgets.json by taking the larger budget per spec. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This branch has not been deployed
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.
Make iframe previews local-first, with an external-origin warning and allowlist
The iframe proxy fronted any http:// upstream it was handed, stripping a remote site's framing headers and CSP and serving it from the shared loopback hostname, with nothing telling the user that a remote page had lost the protections its author relied on. And a frame load redirected off the grant's upstream origin was forwarded verbatim, so the webview's loopback-only frame-src refused it as a blank pane.
The grant is the only chokepoint that matters: both webview CSPs admit only loopback frames, so a remote page reaches a pane only through a minted grant. So the proxy now classifies an upstream by the addresses the grant is pinned to (every one reaching this machine: loopback,
0.0.0.0/::, or an address one of this host's interfaces holds; never the hostname) and refuses a non-local one asexternalunless the request says the user allowed its exact origin; a leased external grant is not reused once the allowance is withdrawn. Each host forwards only an exactallowExternal: true.The panel shows an "External website preview" warning with Open in browser, Allow this origin, and Cancel. Allowed origins persist per host install in localStorage, listed and removable in Settings -> General; allowing or removing one re-asks the host, so a removal closes an open preview.
A frame load redirected to another origin is answered with a Dormouse page that posts
navigateto the app, which takes it as a URL-bar entry through the same gate, replacing the redirecting history entry; a frame nested in a proxied page follows the redirect itself, outside the webview CSP.Cookies stay stripped and https:// stays refused; in-place following of off-proxy links and forms, and cookie support, stay under ## Future.
Closes #572.
Add a Storybook story for the external website preview warning
Exports ExternalPreviewPrompt so its layout and actions have a story: each action reaches its own handler, a host with no system browser drops Open in browser, and a long origin wraps in a narrow pane.
Audit the iframe external-origin gate as FAIL IF S294
Ned asked for the gate to be an audited rule. security-local.md -> Browser panes gains a Guarantee row and FAIL IF S294 (claimed by the local domain's local-terminal stream, which already holds that heading); dor-browser.md's two bolded rules become the mechanism pointing at it.
S294 skips S292 and S293, which the unmerged issue-1166-revoke-access-log takes; they sit in retired here only so the ledger lint passes on this branch alone, and come out of retired when the two branches meet.
Defaults confirmed by the maintainer: Open in browser uses the system browser, and the allowlist is kept per install. The gate is audited as
S294.Merge with #1459:
scripts/security-rule-ids.jsonwill conflict. Keepnext: 295and remove 292 and 293 fromretired, since #1459 uses them as live rules (this branch retires them only to satisfy the ledger lint on its own).Fixes #572
🤖 Generated with Claude Code