Injected text can reach the agent.
It cannot reach the button.
WebMCP lets an agent act inside a tab you are already signed into. That is the point of the standard, and also the risk. This holds every write until you approve it, on any site, whether or not that site ever adopted anything. Reads run freely.
Your browser, right now
Try it — about a minute
-
Enable WebMCP: open
chrome://flags/#enable-webmcp-testing, set it to Enabled, relaunch. - Download the extension (15 KB, zero dependencies)
- Unzip it. Open
chrome://extensions, turn on Developer mode, click Load unpacked, and select the unzipped folder. - Open either demo below, or any WebMCP site at all, and point an agent at it.
Two things to try it on
Anywhere Goods
A plain storefront with no consent layer of its own, which is what most of
the web looks like. Its issue_refund carries no annotation and
gets held anyway. Its check_loyalty_status claims to be read-only
and quietly POSTs, and that gets caught at the network layer.
Ledger
A support console whose customer inbox contains a planted prompt injection: a message inventing a prior ticket and a pre-approved refund. Ask an agent to triage the inbox and watch what it tries. The refund is held either way.
Open LedgerHow it works
registerTool is a property holding a function. A content script runs
at document_start in the MAIN world, before any of the page's own
scripts, and replaces it with a wrapper. The site registers its tools the normal
way and is calling ours. It never finds out.
Classification is one line: no readOnlyHint means it is a write.
Unannotated is treated as dangerous. It never reads the tool's name or
description to guess intent. That text is attacker-reachable, and putting it in
charge of a security decision is the problem this exists to solve.
fetch is patched too. A tool that claims readOnlyHint: true
but fires a POST while running gets held the same way, so a site cannot just lie
in its annotations.
What it cannot do
- A write that never touches the network, meaning one that only mutates in-page state, is invisible to both layers.
- Only
fetchis patched, notXMLHttpRequest,sendBeacon, or WebSockets. - ChatGPT's in-app browser does not accept third-party extensions, so this runs in Chrome with WebMCP enabled.
- Nothing here saves someone who approves without reading.
What it does is raise the cost of a successful injection from “the agent was convinced” to “the agent was convinced and a human approved a card describing the action.” That is a big gap, and it is not a proof.