diff --git a/index.bs b/index.bs index ce4b956..6adac6c 100644 --- a/index.bs +++ b/index.bs @@ -1883,11 +1883,124 @@ This creates a personalization-to-fingerprinting pipeline where sites can extrac
  • Discrimination risk: Extracted attributes (age, pregnancy status, location) could be used for price discrimination or biased service
  • -

    Violation of Same-Origin Boundaries

    +

    Interaction with the Same-Origin Policy

    -

    - TODO: Document risks and implications of [=agents=] carrying state from one origin to another. Detail how tools executed on one origin may carry state from another origin, potentially leading to data leakage or same-origin policy bypasses if not handled securely by the [=user agent=]. This section should probably talk about the WebMCP permissions policy and other cross-origin opt in mechanisms. -

    +The Same-Origin Policy (SOP) is the foundational security boundary of the web platform, isolating +documents of different [=origins=] so that one [=origin=] cannot inspect or manipulate the state of +another without explicit consent. + +In WebMCP, a registered tool's {{ModelContextTool/execute}} callback always runs within the +registering {{Document}}'s execution context, with full access to that [=origin=]'s DOM, storage, +and ambient credentials. Consequently, allowing a cross-origin {{Document}} in the frame tree to +discover a tool ({{ModelContext/getTools()}}), invoke it ({{ModelContext/executeTool()}}), and +receive its serialized return value crosses a privilege boundary. Without strict enforcement, a +malicious frame (either a main frame or an embedded frame) could silently invoke privileged +operations or extract sensitive state from another [=origin=]. + +
    Enforcing Same-Origin Isolation via Two-Sided Opt-In
    + +By default, WebMCP enforces strict [=same origin=] isolation: a tool registered via document.{{Document/modelContext}}.{{ModelContext/registerTool()}} is only +visible to and executable by {{Document}}s that are [=same origin=] with the registering +{{Document}} (tool owner). Cross-origin {{Document}}s cannot discover, observe +{{ModelContext/toolchange}} events for, or execute a tool unless three independent access-control +gates are satisfied: + +
      +
    1. + Embedder Delegation via Permissions Policy (allow="tools"): Access + to all WebMCP APIs ({{ModelContext/registerTool()}}, {{ModelContext/getTools()}}, and + {{ModelContext/executeTool()}}) is gated behind the "{{tools}}" [=policy-controlled feature=], + whose [=policy-controlled feature/default allowlist=] is [=default + allowlist/'self'=]. Consequently, a cross-origin <{iframe}> cannot register or expose + tools—nor will an ancestor's {{ModelContext/getTools()}} traversal inspect that subframe—unless + the embedding {{Document}} explicitly delegates the "{{tools}}" feature to the subframe via + <iframe allow="tools">. +
    2. +
    3. + Tool Provider Opt-In ({{ModelContextRegisterToolOptions/exposedTo}}): A + {{Document}} registering a tool must explicitly opt in to cross-origin exposure by specifying + the permitted caller [=origins=] in {{ModelContextRegisterToolOptions/exposedTo}}. Each listed + [=origin=] must be a valid, [$is origin potentially trustworthy?|potentially trustworthy$] + [=origin=]. During both discovery ({{ModelContext/getTools()}}) and invocation + ({{ModelContext/executeTool()}}), the [=user agent=] evaluates the [=tool is exposed to an + origin=] algorithm, ensuring that only callers whose [=Document/origin=] is [=same origin=] with + the tool owner or explicitly listed in {{ModelContextRegisterToolOptions/exposedTo}} can access + the tool. +
    4. +
    5. + Tool Consumer Opt-In ({{ModelContextGetToolOptions/fromOrigins}}): Even when an + embedded cross-origin {{Document}} has been delegated allow="tools" and has exposed + a tool to its parent [=origin=] via {{ModelContextRegisterToolOptions/exposedTo}}, + {{ModelContext/getTools()}} only returns tools from [=same origin=] {{Document}}s by default. To + discover tools from a cross-origin descendant [=navigable=], the calling {{Document}} must also + explicitly list the target [=origin=] in {{ModelContextGetToolOptions/fromOrigins}}. +
    6. +
    + +**Why Two-Sided Opt-In Matters**: Requiring mutual consent from both the tool provider +({{ModelContextRegisterToolOptions/exposedTo}}) and the tool consumer +({{ModelContextGetToolOptions/fromOrigins}}) prevents both unauthorized cross-origin actuation and +unsolicited tool-list pollution. Without provider opt-in +({{ModelContextRegisterToolOptions/exposedTo}}), a malicious parent page could invoke internal tools +inside an embedded third-party widget that were intended only for [=same origin=] use. Conversely, +without consumer opt-in ({{ModelContextGetToolOptions/fromOrigins}}), a compromised or untrusted +third-party <{iframe}> could unilaterally expose tools with deceptive names or prompt-injected +descriptions ([[#metadata-description-attacks]]) into the parent page's {{ModelContext/getTools()}} +results. + +```js +// 1. Parent document (https://app.example.com) explicitly delegates the "tools" +// feature to the embedded widget (