Skip to content

web: sandbox hardening — opaque-origin inner frame, srcdoc-only delivery, frame-ancestors CSP #1565

Description

@cliffhall

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).

Metadata

Metadata

Assignees

Labels

v2Issues and PRs for v2

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions