november 2026 · 6 min

Your Browser Session Is a Desktop Credential

A browser extension that can run script on claude.ai can make Claude Desktop install an npm package on your machine. It doesn't need an exploit, a stolen password or a second device. It needs the tab you already have open.

Once a web session can steer an agent on your laptop, that session is a credential for your laptop. And every extension that can read the page holds a copy of it.

The Mechanism

ThisBash, from Gal Weizman at Forever Security, goes through Dispatch, the feature that lets you send work from claude.ai to Claude Desktop. Dispatch takes a signed-in claude.ai session as proof that you're the one sending. The Register's walk-through lays out the chain:

  1. The extension injects a script into claude.ai that runs in the page's own context, so the page's session works for it too.
  2. It opens Dispatch in a small, unfocused popup. Dispatch has no link in the UI, but it answers at its URL.
  3. It uses the session to query the sessions endpoint and find the desktop agent.
  4. It sends prompts. The agent hesitated at first, so the script sent four prompts, plus a follow-up written as if it came from you.
  5. The approval prompts show up in the web page. A one-second timer clicks any button labelled Allow.
  6. Claude Desktop runs a global npm install. The package's preinstall hook opened Calculator.

The PoC extension asks for scripting and <all_urls>. That's the same permission set your ad blocker, grammar checker and half the "productivity" extensions on the store already hold.

The approval in step 5 is the control people rely on, and it rendered in the one place the attacker already controlled. A script clicking Allow doesn't count as consent.

Why a Session Is the Wrong Proof

Forever's line is the right one: "an authenticated web session is not, by itself, evidence that the user authorized a command on their machine." A session cookie proves a browser signed in at some point. It says nothing about who is typing, or which code in that browser is acting.

That was fine while the worst thing a session could do was read your chats. It stopped being fine when the same session could issue commands to a process with a shell. Weizman's fix, per The Register, is to treat the web client as a separate device with fewer permissions, and he points to Codex keeping its web and desktop sessions apart.

This is a class, not one bug. In May, ClaudeBleed showed the Claude in Chrome extension trusting the claude.ai origin, so a page script could send it prompts and forge approvals. In September, BragJack used extensions to hijack the agents built into Gemini, Comet, Edge and Opera. ThisBash is the same move, except the agent sits outside the browser.

Where It Stands

It was reported on May 14 and closed on May 19 as a duplicate of an issue Anthropic had found internally. Forever says Anthropic stated on October 13 that Dispatch would be retired by the end of October. The Register says the support page on October 30 still listed it as a limited beta, closed to new users, with existing users able to keep it "for now."

Forever also says Remote Control and Cowork are built the same way. It hasn't tested that and promises a follow-up. Until it shows something, treat that as a claim. Retiring one feature doesn't retire the pattern: any vendor that lets a browser tab drive a local agent has this exposure, unless the approval happens outside the page.

The Check and the Control

First, find out what can read the page. On macOS, for Chrome:

grep -lE '<all_urls>|"(\*|https?)://\*/|claude\.ai' \
  ~/Library/Application\ Support/Google/Chrome/*/Extensions/*/*/manifest.json

Every hit is a candidate: an extension that asks for every site, or mentions claude.ai somewhere in its manifest. Read the manifest to see which. The directory name is the extension ID. This covers Chrome only, and it misses access requested later through optional_host_permissions. On Linux the path starts at ~/.config/google-chrome/.

Then take the agent's control origin away from extensions. Chrome and Edge both support runtime_blocked_hosts in the ExtensionSettings policy. Chrome's docs describe it as a way to "Prevent extensions from interacting with or modifying websites that you specify", covering script injection and cookie access. Here's the form from Microsoft's policy reference:

{
  "*": {
    "runtime_blocked_hosts": ["*://*.claude.ai"]
  }
}

Firefox has restricted_domains in the "*" block, which stops content scripts on those domains, and runtime_blocked_hosts from Firefox 153.

Add every origin that can send commands to an agent on the machine, not just this one. If you don't use Dispatch, turn it off and revoke the pairing.

The Tradeoff

The block hits every extension on that site, the ones you want included. Password managers and Claude's own Chrome extension stop working there, and you'll be writing runtime_allowed_hosts exceptions per extension ID. Microsoft's doc says a per-extension entry inherits only installation_mode and update_url from "*", so an extension with its own entry doesn't get the block. Check what you actually deployed. And all of this is a patch on the client, not a fix to the design.

I think the root is a familiar one: we take a human-era primitive (a login cookie, a dialog with a button) and ask it to carry an agent-era decision. Agents need a channel where an approval comes from the machine that runs the command, not from whatever page can draw a button. Until vendors ship one, keep extensions away from any origin that can reach your shell.

← all posts