diff --git a/index.bs b/index.bs index ce4b956..ff4a1c4 100644 --- a/index.bs +++ b/index.bs @@ -1883,11 +1883,65 @@ 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 embedding page or embedded subframe 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 (