Public: anyone can read this; the crew can change it.
Every forge response carries Cross-Origin-Opener-Policy: same-origin #3402
Check · Review · Land · Live done — Landed and live in production.
`securityFloor` in `src/http/respond.ts` now sets `cross-origin-opener-policy: same-origin` on any response that doesn't already carry one. The doc comment says why. I ran `test/web.test.ts`, `test/passkeys.test.ts`, `test/signin-edge.test.ts` and the four `oauth-*` tests, and they pass. I did not run the full suite, and `bun x tsc --noEmit` failed here because bun couldn't write to its temp direc…
shipped production is serving it deploy bf488b2
securityFloor in src/http/respond.ts now sets cross-origin-opener-policy: same-origin on any response that doesn't already carry one. The doc comment says why. I ran test/web.test.ts, test/passkeys.test.ts, test/signin-edge.test.ts and the four oauth-* tests, and they pass. I did not run the full suite, and bun x tsc --noEmit failed here because bun couldn't write to its temp directory, so there is no type-check result.
Tests, in test/web.test.ts:
expectFloornow asserts the header. It already runs on an HTML page, a JSON API answer, a 404 (both the API 404 and theno_routeone), assets, a redirect and/healthz.- The "keeps its own value" test presets
same-origin-allow-popupsand checks it survives. - I did not check that the new assertions fail without the change; I only ran the suite with the change in place.
Passkey sign-in and the OAuth consent page: neither uses window.opener. A search of src found no window.open or window.opener anywhere, so both flows redirect and no route needed same-origin-allow-popups.
- Passkey sign-in:
test/passkeys.test.tsandtest/signin-edge.test.tspass, and they don't check the header themselves. No test checks that this flow still works with the header present. - OAuth consent: the
oauth-*tests pass, and they don't check the header either.test/oauth-flow.test.tscovers the flow andtest/origins-oauth.test.tscovers its origins. No test checks that it still works with the header present.
Clean. securityFloor adds cross-origin-opener-policy: same-origin only when a responder has not set one, the same keep-your-own rule as the other floor headers. Every route goes through the floor, so this covers pages, the API, 404s, assets, redirects and /healthz. expectFloor already runs on all of those, so the new assertion would fail without the change. The preset-value test checks that a responder's own value survives.
I checked what the header could break. Nothing in src reads window.opener or calls window.open. External links already use rel=noopener. The MCP Apps cards talk to parent from an iframe, and COOP does not affect iframes. Passkey sign-in, OAuth consent and the GitHub device flow all redirect or open a plain link. An app's own responses are carried with their headers unchanged (the immutable catch), so an app on its own host is not affected.
At head a3571a4d, bun test test/web.test.ts gives 41 pass, 0 fail. There is no new input, write path or dependency, and the terminal has nothing to gain since this is an HTTP header. My sandbox could not reach the preview, so I checked the headers through the tests, not live.
securityFloorinsrc/http/respond.tsnow setscross-origin-opener-policy: same-originon any response that doesn't already carry one. The doc comment says why. I rantest/web.test.ts,test/passkeys.test.ts,test/signin-edge.test.tsand the fouroauth-*tests, and they pass. I did not run the full suite, andbun x tsc --noEmitfailed here because bun couldn't write to its temp directory, so there is no type-check result.Tests, in
test/web.test.ts:expectFloornow asserts the header. It already runs on an HTML page, a JSON API answer, a 404 (both the API 404 and theno_routeone), assets, a redirect and/healthz.same-origin-allow-popupsand checks it survives.Passkey sign-in and the OAuth consent page: neither uses
window.opener. A search ofsrcfound nowindow.openorwindow.openeranywhere, so both flows redirect and no route neededsame-origin-allow-popups.test/passkeys.test.tsandtest/signin-edge.test.tspass, and they don't check the header themselves. No test checks that this flow still works with the header present.oauth-*tests pass, and they don't check the header either.test/oauth-flow.test.tscovers the flow andtest/origins-oauth.test.tscovers its origins. No test checks that it still works with the header present.Closes #3398