← Back to all posts
Published on · by Renaud Deraison

The update added a key

For eleven hours on October 29, Cursor's extension marketplace served a trojanized Claude Code extension under Anthropic's own publisher name. On load, it added an attacker's SSH key, installed a LaunchAgent and tried to open a reverse tunnel, on up to 5,000 developers' machines. In Bromure Agentic Coding, the agent doesn't come from an editor marketplace, and a payload like this one runs in a VM nobody can reach, with its tunnel refused by the egress firewall and its persistence removed by rewinding the home.

Nobody had to open a chat or approve a tool call. The editor loaded the extension, and 66 lines of JavaScript ran as the developer before Claude Code's own code did.

On October 29, between about 2:27 a.m. and 1:35 p.m. Pacific time, Cursor's extension marketplace served a trojanized build of Anthropic's Claude Code extension. Cursor's security notice names versions 2.1.312 and 2.1.313 of anthropic.claude-code, published under Anthropic's publisher identity, and says Anthropic didn't build them. BleepingComputer reports that up to 5,000 developers were exposed, and The Hacker News notes that anyone with auto-update turned on could have received it without doing anything.

Researchers at Phorion and OpenSourceMalware published analyses on October 30. Cursor pulled the extension, shut its marketplace down to audit it and rotate keys, and had the attacker's server taken offline. Nobody has said yet how the build got published under Anthropic's name.

What the 66 lines did

The attacker left Claude Code's code alone and put a 66-line loader in front of it, at the top of extension.js. OpenSourceMalware describes the pattern: "place a compact backdoor before a large legitimate bundle, suppress errors, and let the expected application continue." The loader ran when the editor loaded the extension and opened its webview. The developer didn't have to start a conversation. After that, the real extension loaded and worked.

In the meantime, the loader:

  1. Took an inventory. Hostname, username, OS, home and working directories, the global git email, the public IP, and the names of up to 40 environment variables containing KEY, TOKEN, SECRET, PASS, AWS or GCP. It sent all of it as JSON, over plain HTTP, to 134.209.82.225:8099/beacon.
  2. Added a door. It appended an Ed25519 key with the comment svc-telemetry to ~/.ssh/authorized_keys.
  3. Tried to open it. On macOS it ran sudo -n systemsetup -setremotelogin on, on Linux it tried to start sshd, and on Windows it installed OpenSSH Server.
  4. Dialed out. It wrote a private key to a temp file and connected to [email protected] with -N -R '*:0:localhost:22', a reverse tunnel that forwards a port on the attacker's server back to the developer's own SSH port. It reconnected every 60 seconds.
  5. Made itself permanent. A user LaunchAgent named com.apple.sysmond on macOS, a crontab @reboot entry on Linux, and a scheduled task called SysMon on Windows.

Coding errors kept SSH from switching on for many victims, according to BleepingComputer. The key, the persistence and the beacon landed on those machines too. Cursor's advice is to check for the svc-telemetry key, remove the persistence, consider rebuilding the machine because uninstalling the extension may not be enough, and rotate every credential the machine could reach, "using a trusted system."

From an extension update to an attacker's key on the machineEditor loads it2.1.312 / 2.1.313,Anthropic's name,auto-updated1 · Inventoryhost, user, git email,public IP, names ofKEY / TOKEN vars2 · Keysvc-telemetry addedto authorized_keys,SSH switched on3 · Persistencecom.apple.sysmond,crontab @reboot,SysMon task4 · Call homereverse tunnelon :22, beaconon :8099An attacker's key and a way back in, on the developer's own accountnext to ~/.ssh, ~/.aws, the gh login and every repository; Cursor's advice: consider rebuilding the machine
What the trojanized Claude Code extension did on load, per Cursor's notice and OpenSourceMalware's analysis. A 66-line loader in front of the real extension took an inventory, added an attacker's SSH key, installed persistence, and opened a reverse tunnel and an HTTP beacon to 134.209.82.225.

The most trusted code on the machine

An editor extension runs with the developer's full account. It can read every file in the home directory, start processes, and write a LaunchAgent that outlives the editor. Marketplaces push updates without asking, and the publisher name on this one was Anthropic's. A cautious developer who checked the publisher before installing got the backdoor too: it arrived as an update to an extension they had installed weeks earlier.

Coding agents raise the stakes. The extension that hosts the agent is the one developers grant the most: it reads the whole repository, runs commands, and sits in a process with the environment's API keys and cloud tokens. This loader took the names of those variables. Reading the values takes the same few lines.

The same morning in Bromure Agentic Coding

Bromure Agentic Coding runs Claude Code, Codex, Grok, Kimi and omp in Ubuntu VMs on your Mac. Each machine is a VM of its own, and the agent, its repositories, its package installs and its commands all live inside it. The chat and the terminals you type into are drawn by the app on your Mac. The real credentials, the proxy the VM's traffic goes through, and the record of what happened stay on the Mac too.

The agent doesn't come from an editor marketplace

There's no extension marketplace in the path: Bromure draws its own chat window on the Mac. Claude Code is installed into your copy of Bromure's base image by a setup step listed in a catalog signed with the same key as Bromure's app updates. That step installs @anthropic-ai/claude-code from npm, wrapped in Socket.dev's supply-chain scanner. OpenSourceMalware lists the npm package among the distributions that weren't touched.

Anything the agent installs afterwards goes through the proxy on the Mac, and the proxy applies the machine's supply-chain policy. The age gate ships on, with a two-day minimum: npm, PyPI, Cargo, RubyGems and Packagist versions younger than that are removed from the registry's listing, so latest resolves to the newest release that has been public for two days. Cursor's malicious build was live for eleven hours. A hijacked release on npm with the same lifetime never appears in a Bromure machine. We walked through that case with LiteLLM's poisoned PyPI release in The release was two hours old.

The key opens a door nobody can reach

Say a payload like this one gets into a machine anyway, through a repository the agent clones or a tool it runs. It runs in Ubuntu, as the machine's user. It doesn't get your macOS account, your Keychain or your Mac's ~/.ssh.

Its svc-telemetry key goes into the VM's own authorized_keys. Machines sit on a private network inside the app: your Mac can reach them, your physical LAN can't, and nothing outside can connect unless you publish a service yourself. The only route in was the reverse tunnel.

The tunnel never opens

The tunnel needs an outbound SSH connection to 134.209.82.225, and the beacon needs plain HTTP to port 8099 on the same address. Every connection the VM makes passes through the Mac, where the machine's Outbound connections firewall applies. Its rules match host, IP range, protocol and port, and with Unmatched traffic set to Deny only the hosts you listed get through. A DigitalOcean IP on port 22 isn't on anyone's list. The firewall refuses the tunnel, each 60-second retry, and the beacon.

Each refusal lands in the Security Timeline on your Mac, with the host, port, protocol and verdict. A deny to the same IP every minute is hard to miss, and you see it while the attacker waits for a connection.

The inventory is worth nothing

The beacon's list of variable names would have found plenty in a Bromure machine: ANTHROPIC_API_KEY, a GitHub token, AWS settings. Every value is a stand-in. The real credentials are encrypted on the Mac, and the proxy swaps a stand-in for its real value only on requests to the host it belongs to. SSH private keys aren't in the VM at all. SSH_AUTH_SOCK is a bridge to the Mac that returns signatures, and your Mac's own ssh-agent is never exposed. A loader that went on to read the values would get strings that no server accepts. If it sent one of them to its own server, the proxy would block the request, pause the VM and show This environment may have been compromised, naming the credential and the destination.

The cleanup takes a minute

Cursor tells affected developers to remove the key and the persistence, consider rebuilding the machine, and rotate credentials from a trusted system. In Bromure, the rebuild is two menu items. Bromure keeps a copy-on-write checkpoint of each machine's home every time it boots. Rewind home… rolls /home/ubuntu back to a boot from before the payload ran, taking the extra key and the ~/.config/.smt launcher with it. Reset disk re-clones the system disk from the base image and takes the crontab with it. The machine's settings, credentials and SSH keys survive both.

The trusted system Cursor asks for is the Mac, which never ran the payload. There's nothing to rotate, because the VM never held a real credential.

Editor on a laptop: the loader runs as youThe extension auto-updates and loadsin your macOS account, next to your real keysKey and persistence on the Macsvc-telemetry in ~/.ssh/authorized_keys,LaunchAgent com.apple.sysmondStraight to 134.209.82.225reverse tunnel on :22 every 60 s, beacon on :8099;fix: rebuild the machine, rotate everythingBromure: the payload runs in a VMMachine VM (Ubuntu)key in the VM's own authorized_keys; stand-ins onlyevery connection via the MacEgress firewall on your Mac134.209.82.225:22 tunnel: deny134.209.82.225:8099 beacon: denyeach attempt in the Security Timelinethen, with the machine offRewind home… and Reset diskkey, launcher and crontab gone; settings and keys kept
The same payload in a Bromure machine. It runs in the machine's Ubuntu VM, adds its key to the VM's own authorized_keys on a network nobody outside can reach, and finds only stand-in credentials. Its tunnel and beacon go through the Mac, where the egress firewall refuses them and the Security Timeline records each attempt. Rewind home and Reset disk remove the persistence; the Mac and its real credentials are untouched.

Give the risky work its own machine

Credentials and firewall rules are set per machine, and machines are cheap to make. A machine that tries out new tools, plugins and starter kits can have no production credentials and a firewall that denies everything except its package registries. The machine that deploys keeps its credentials, with approval required before each one is used. For a one-off experiment, bromure-cli vm run --rm creates a machine that is deleted when it stops.

No marketplace in the path

The chat is part of the app. Claude Code comes from Anthropic's npm package through a signed setup step, scanned by Socket.dev.

Two days before anything new

The age gate hides package releases younger than two days. A hijacked version that lives eleven hours never resolves.

A door nobody can reach

A planted key lands in the VM's own authorized_keys, on a private network your LAN and the internet can't connect to.

Deny the unknown host

With Unmatched traffic set to Deny, the reverse tunnel and the beacon are refused, and every attempt is recorded on the Mac.

Stand-ins in the VM

Every API key and token in the VM is a stand-in, and SSH private keys never enter it. The inventory is worth nothing.

Rewind instead of rebuild

Rewind home and Reset disk remove the payload's files and persistence. Settings, credentials and keys stay.

The tool that runs the agent is part of the attack surface

Cursor and Anthropic haven't said how the build went out under Anthropic's name. For your own machine, the incident settles one point. The software that hosts your coding agent runs with your account and updates itself, and a trusted publisher name on the update proves nothing about its contents.

In Bromure Agentic Coding, your agent and everything it touches run in a VM on your Mac. That VM holds stand-ins, reaches only the hosts you allow, and can be rolled back to a boot from before something went wrong. The real keys never leave the Mac.

For infostealers that now collect coding agents' tokens and histories, read They added your agent. For a compromise that started on a developer's laptop and ended at $6.3 billion, read The laptop was the way in.