Summary
Harden the MCP Apps sandbox isolation model:
- The inner (untrusted-widget) iframe is sandboxed without
allow-same-origin — default it off and strip it (case-insensitively) from any server-supplied sandbox value — so the widget runs under an opaque origin and cannot reach the proxy's DOM to bypass its own CSP via the parent realm.
- Widget delivery is
srcdoc-only (no document.write), which respects the opaque origin.
- The relay accepts the inner frame's
"null" origin with event.source === inner.contentWindow as the identity check.
sandbox-controller.ts serves the proxy with Content-Security-Policy: frame-ancestors http://127.0.0.1:* http://localhost:* so only the inspector itself can embed it. Fetch directives are deliberately omitted — srcdoc inherits the parent's policy container, so a default-src here would intersect with and override the per-app CSP.
Reference implementation (PR #1510)
Re-implement informed by these changes at 33fac3f:
Depends on
- Recommended before the CSP-enforcement wiring issue (they define the isolation model together), but has no hard code dependency. Wave 2 lane start.
Notes
- Keep AGENTS.md /
clients/web README's description of the sandbox model up to date (docs rule).
- Verify the MCP Apps tab still renders an existing widget end-to-end after the change (the
mcp_app_demo preset from the test-servers issue is the fixture for this).
Part of the PR #1510 decomposition (see tracking issue).
Summary
Harden the MCP Apps sandbox isolation model:
allow-same-origin— default it off and strip it (case-insensitively) from any server-supplied sandbox value — so the widget runs under an opaque origin and cannot reach the proxy's DOM to bypass its own CSP via the parent realm.srcdoc-only (nodocument.write), which respects the opaque origin."null"origin withevent.source === inner.contentWindowas the identity check.sandbox-controller.tsserves the proxy withContent-Security-Policy: frame-ancestors http://127.0.0.1:* http://localhost:*so only the inspector itself can embed it. Fetch directives are deliberately omitted —srcdocinherits the parent's policy container, so adefault-srchere would intersect with and override the per-app CSP.Reference implementation (PR #1510)
Re-implement informed by these changes at
33fac3f:INNER_ORIGIN = "null"check,srcdocdelivery, updated isolation-model comment (+58/−33)frame-ancestorsheader (+13)Depends on
Notes
clients/webREADME's description of the sandbox model up to date (docs rule).mcp_app_demopreset from the test-servers issue is the fixture for this).Part of the PR #1510 decomposition (see tracking issue).