State of WebMCP security, October 2026
We scanned 600 sites in a headless browser, 548 of them expected to use WebMCP and the rest a control group, and listed every tool they registered without calling any of them. This page reports what we saw, cohort by cohort, and what site owners can change.
What WebMCP is
WebMCP lets a web page register tools (a name, a description, a JSON Schema for the input and a JavaScript callback) with document.modelContext.registerTool(), so an AI agent running in the browser can call them instead of reading and clicking the page. The tools run inside the page with the user's live session, and the spec offers advisory annotations (readOnlyHint, consequentialHint, untrustedContentHint) to tell the agent what a tool does.
Methodology
- Browser. chrome-headless-shell 153 with
--enable-features=WebMCP(passed together with Playwright's own feature flag), no origin-trial token. All runs were headless. - Enumeration only. We loaded each homepage logged out and read the tools it registered. We never called a tool, clicked or submitted anything.
- Run. First pass at concurrency 5 with a 30 s timeout. The 43 sites that hit a timeout or network error were rerun once at 60 s and concurrency 3, keeping the better record; 40 recovered. 597 of 600 loaded. The three that still failed: washingtonpost.com (HTTP/2 protocol error), webmcp.basgr.com (connection timed out) and docs.opentiny.design (60 s timeout).
- Sample. The 600 sites are not a random sample of the web. Most cohorts were picked because they were expected to use WebMCP, plus a control group of popular sites that were not. We report counts per cohort, not ecosystem percentages.
- Adoption. With the flag on, Chromium exposes
document.modelContexton every page (all 597 loaded sites had it), so that only shows the setup worked. A site counts as using WebMCP when it registers at least one tool on load. - Coverage. Homepage only. Tools that appear after login, on product, cart or checkout pages, or after interaction are not counted, so every tool count is a floor.
- Checks. Write shape (does the name or description say it changes state), PII-shaped parameters, prompt-injection patterns in descriptions, schema validity, descriptions over 500 characters (our threshold; the draft spec sets no limit), which script called
registerTool, and thePermissions-Policyheader. These are heuristics, and we reviewed every prompt-injection, read-only and PII hit by hand. - Who registered each tool. From the script URL in the captured stack, each tool is first-party (the page's own domain), platform (a hosting platform's own script, such as Shopify's under
cdn.shopify.com/shopifycloud/on a Shopify store), library (a package from a public npm CDN such as unpkg or jsDelivr, which the page author chose) or third-party (any other domain). The sites whose tools came from another domain in the first pass, plus one more Shopify store for comparison, were rescanned with this classification the same day, and those records replace the first-pass ones.
Headline findings
188 of the 597 loaded sites registered at least one tool on the homepage, 1,657 tools in total. Shopify's storefront script registers the same 12 tools on 92 of those sites, which is 1,104 of the 1,657 tools. Merchants cannot change those tools, so every metric is shown both ways.
| Metric | All tools | Excluding Shopify's tools |
|---|---|---|
| Sites with at least one tool | 188 (31.5%) | 96 (16.1%) |
| Tools | 1,657 | 553 |
| Write-shaped tools (upper bound) | 416 | 48 |
| ... marked neither consequential nor read-only | 406 (97.6%) | 38 (79.2%) |
| ... marked readOnlyHint: true | 4 | 4 |
| Tools from a public npm CDN (library) | 15 (2 sites) | 15 (2 sites) |
| Tools from another domain (third-party) | 1 (1 site) | 1 (1 site) |
| Descriptions matching an agent-instruction pattern | 92 | 0 |
| Descriptions over 500 characters | 563 | 11 |
- Confirmation hints are rare. Only 8 tools in the whole sample set
consequentialHint. Of 416 tools whose name or description says they change state, 406 are marked neither consequential nor read-only; outside Shopify it is 38 of 48. These write-shaped counts are an upper bound: the heuristic reads names and descriptions, so it also counts tools that only return a link or a quote. - Read-only hints on write-shaped names. 4 write-shaped tools are marked
readOnlyHint: true. On review, three of them only return a link or a price quote according to their descriptions, so the hint fits and the name triggered the heuristic. The fourth,remove_nodeon the webmcp-flow.vercel.app demo, deletes a node and should not be marked read-only. - Agent-directed instructions. The prompt-injection patterns matched 92 times, all on one description: Shopify's
add_to_cart, which tells the agent “do NOT ask the user to confirm” before adding to the cart. It appears on 92 storefronts: the 91 in our Shopify cohort that registered tools, and 1 Shopify store in the Known Good cohort. Outside Shopify's tools there were no matches. - Who registers the tools. 1,628 of 1,657 tools were registered by a script on the page's own domain, including every Shopify platform tool (Shopify serves that script from the shop's domain), and 13 had no script URL. 15 tools on 2 sites came from WebMCP helper libraries on public npm CDNs (
simple-webmcp@0.3.0from unpkg on the emingure.github.io demo, and@willh/agentready@latest, an unpinned version, from jsDelivr on agentready.gh.miniasp.com). One tool on one site came from another domain: target.com'ssearch_products, from assets.targetimg1.com, which looks like Target's own asset domain. We saw no outside vendor injecting tools. In the first pass one Shopify store loaded Shopify's script fromcdn.shopify.com; on the rescan it came from the store's own domain, and the audit now classifies thecdn.shopify.com/shopifycloud/path as platform code. - PII. 14 tools take parameters shaped like personal data (email, phone, address). The heuristic flagged 2 as asking for more than the tool needs; on review both prefill a contact or quote form that is then sent from the page's own form, with the extra field optional, so we do not count them as over-collection.
- Schemas and descriptions. No tool had a missing or malformed input schema. 563 descriptions are longer than 500 characters, but only 11 of them are outside Shopify.
- Permissions-Policy. 32 of the 188 tool sites send the header, and 5 of those include a
tools=(self)rule. Across all loaded sites, 7 send atoolsrule; 2 of them registered no tools on the homepage.
By cohort
| Cohort | Sites with tools | Tools | Write-shaped | No consequentialHint |
|---|---|---|---|---|
| Listed as WebMCP sites by Known Good | 37 / 336 | 157 | 21 | 14 |
| Shopify Online Store storefronts | 91 / 100 | 1,092 | 364 | 364 |
| Cloudflare bridge, Vercel mcp-handler, open-source adopters | 24 / 52 | 134 | 10 | 10 |
| Brands Google showed at I/O 2026, and showcase sites | 36 / 58 | 274 | 21 | 18 |
| Control: popular sites not expected to use WebMCP | 0 / 51 | 0 | 0 | 0 |
- The control group registered nothing: 0 of 51, so we saw no false adoption there.
- We found the candidates for the first cohort through Known Good, a directory of sites it lists as WebMCP users, and report that cohort only as totals. Only 37 of its 336 sites (11%) registered a tool on the homepage in our browser run. A static check of the homepage HTML of the other 299 (11 October 2026; we fetched the HTML once and searched it, without running it in a browser) suggests why: 265 of them reference only the old
navigator.modelContext, which Chrome removed in M152, and 220 useprovideContext, which the current draft no longer defines. In Chrome 153 that code finds no API and registers nothing, so for most of these sites the gap looks like a change in the browser API rather than an error in the directory. - Most tools in the origin-trial and showcase group come from showcase sites (32 of 45 register tools). Of the nine consumer brands Google showed as experimenting with WebMCP at Google I/O 2026, only target.com registered a tool on its homepage.
- 91 of 100 Shopify storefronts registered the platform tools.
Shopify: a platform-default hint gap
Shopify's changelog of 5 August 2026 says WebMCP tools are live on every Liquid storefront with nothing to install or configure. On a homepage that is 12 tools: catalog and policy search, product and variant views, cart reads and edits (add_to_cart, update_cart_lines, cancel_cart), proceed_to_checkout and manage_orders. Four of the read tools set readOnlyHint and nine tools set untrustedContentHint, so Shopify does use the annotations. None of the state-changing tools sets consequentialHint.
That is not the same as “Shopify stores let agents buy without asking”. Placing an order is a separate tool, complete_checkout, which lives on checkout pages we did not scan. Shopify's checkout changelog describes it as submitting checkout “after buyer confirmation”. Adding to a cart is reversible, and the add_to_cart description's instruction not to ask for confirmation is a design choice for that reversible step.
The gap is in the machine-readable signal. An agent that decides when to ask the user by reading consequentialHint gets no signal from these tools, and a scanner that looks for agent-directed instructions will flag the add_to_cart description on every store. Both are one change at the platform level, not 92 merchant problems: the tools come from Shopify's script, not from merchant code.
What site owners should do
- Mark writes. Set
consequentialHint: trueon any tool that buys, books, sends, deletes, changes an account or spends money. - Use readOnlyHint only for true reads. A tool that books, signs up or removes something is not read-only. A tool that only returns a link is, and a clear description saves reviewers from guessing.
- Keep descriptions short and factual. Say what the tool does and what it returns. Avoid instructions aimed at the agent about whether to ask the user; that decision belongs to the agent and the user.
- Authorize on the server, for every tool. Hints are advisory and a tool runs with the user's session. Check permissions and require confirmation for consequential actions on the server, as you would for a form post.
- Ask only for the data the tool needs. Mark optional contact fields as optional and say in the description why the tool asks for them.
- Send
Permissions-Policy: tools=()on pages that should register no tools. Account, admin and payment pages are good candidates. The default allowlist,self, already keeps cross-origin frames out, but scripts you load into the page run as your origin, so onlytools=()stops them. - Watch third-party scripts. Any script on the page can call
registerTool, including analytics, chat and A/B-testing tags. Review what your tag manager loads, pin helper libraries to a version (one site in the scan loads@latestfrom a CDN), and check the tool list after each deploy.
Status of the standard
- Spec. A W3C Web Machine Learning Community Group draft (9 October 2026), not a W3C Recommendation-track document. The current API is
document.modelContext; the earliernavigator.modelContextwas removed in Chrome 152. - Chrome. Origin trial from M149 to M156; Chrome Platform Status lists a requested extension to M162.
- Other engines. WebKit has taken an “oppose” position; Mozilla's position is neutral.
- Next decision point. W3C TPAC, 26-30 October 2026 in Dublin. Expect API changes.
- Agents that call WebMCP tools. ChatGPT's desktop app calls site tools in its built-in browser for ChatGPT Work and Codex. Playwright 1.64 exposes them as
page.webmcp. At Google I/O 2026 Google said Gemini in Chrome “will soon support” WebMCP; we found no announcement that it has shipped.
Run it yourself
The audit behind this report is a new vskill command. It loads one URL headless, lists the tools and prints the same checks, without calling any tool. It ships in vskill 1.2.6 and later (source in the vskill repository):
npx vskill@latest audit-webmcp https://your-site.example
To inspect tools by hand, start Chromium 153 or later with --enable-features=WebMCP. Under Playwright, merge it with Playwright's own flag as --enable-features=CDPScreenshotNewSurface,WebMCP; a second --enable-features argument replaces the first.
Limits of this audit
- The registrar check cannot tell a site's own asset domain from an outside vendor: a script from assets.targetimg1.com on target.com counts as third-party. Only one hosting platform (Shopify) is known to the platform rule so far.
- Write shape is inferred from names and descriptions. A tool named
signup_urlthat only returns a link is flagged the same way as one that creates an account, so the write-shaped counts are an upper bound. - Sites from the Known Good cohort appear only in totals. Elsewhere we name a site only where it illustrates a finding above, and we publish no per-site verdicts or scores for any site.
- 28 sites also define the old
navigator.modelContext, which Chrome 153 no longer provides, so a page script sets it. We counted tools only throughdocument.modelContext. Sites whose code still targets the old API register nothing in current Chrome and count as zero-tool sites.
Sources and data
Aggregate counts and methodology as JSON: /api/v1/insights/webmcp. It lists no individual sites.
- WebMCP draft specification, W3C Web Machine Learning Community Group (9 Oct 2026)
- WebMCP specification repository and issues
- Chrome for Developers: WebMCP
- Chrome Platform Status: WebMCP
- Chrome at Google I/O 2026 (Gemini in Chrome, brands experimenting with WebMCP)
- WebKit standards position #670 (oppose)
- Mozilla standards position #1412 (neutral)
- W3C TPAC 2026, Dublin, 26-30 October
- Shopify changelog: WebMCP support for Liquid and Hydrogen storefronts (5 Aug 2026)
- Shopify changelog: WebMCP support for checkout (28 Sep 2026)
- Cloudflare: WebMCP edge bridge (6 Aug 2026)
- Vercel changelog: WebMCP in mcp-handler 2.2.0 (18 Sep 2026)
- ChatGPT site tools (WebMCP)
- Playwright 1.64 release notes (page.webmcp)
- WebMCP Tool Surface Poisoning: Runtime Manipulation Attacks on LLM Agents, arXiv 2606.06387
- Chromium change removing navigator.modelContext (WPT sync PR 61186, July 2026)
- Known Good, the directory used to find candidate sites for cohort a