Ok, first things first, because it is the first question: we work with Cursor, and we were not affected. Checked, not hoped. Now the case, because it matters more than the headline. On 29 October, the Cursor Marketplace carried a version of the Claude Code extension that did not come from Anthropic. Same name, same identifier, same function. Only, 66 lines sat in front of it that plant a foreign SSH key, open a back channel and ship machine data. No prompt, no model, no hallucination. The whole incident has exactly one thing to do with AI: we give these tools rights we would give nobody else.
What happened
Version 2.1.313 of the extension "anthropic.claude-code" appeared in the Cursor Marketplace on the morning of 29 October, as a regular update under the real publisher identifier. Anyone with auto-update on received it. In front of the extension's legitimate code sat a 66-line loader. It ran when the editor started; you did not even have to use Claude. It added a key with the harmless name "svc-telemetry" to the "authorized_keys" file, tried to switch on the local SSH service, built a reverse tunnel to a fixed IP address, installed persistence, depending on the system as a scheduled task, crontab entry or LaunchAgent, and sent machine data unencrypted to a beacon on port 8099: public IP, hostname, username, system, git email, and the names of up to forty environment variables containing KEY, TOKEN, SECRET, PASS, AWS or GCP. Not the values. But the names are enough to know which cloud, which CI, which kind of access lives on that machine.
Eleven hours later, at 13:35 Pacific time, the version was gone. Cursor temporarily shut down the whole marketplace, searched for further tampered extensions and found none. Anthropic pushed 2.1.314 to Open VSX and the Microsoft Marketplace. Neither was ever affected, nor was the npm package. Only Cursor's own marketplace.
The chain, and where the model appears in it: nowhere
We have spent a year talking about prompt injection, poisoned training data, agents that drift. Here the attacker needed none of it. Not a single model call was required. This is the security question that has not let go of me since the Binance incident, and it is the same one here: who controls the executable code around the model? An agent can work completely correctly, follow every rule, never sign off its own work, and in the same process a compromised extension is already collecting credentials. The tools we hand development rights to, editor, extensions, MCP servers, agent tools, are the attack surface. Not the model.
How big the damage was
According to Cursor, at most 5,000 users who installed or updated in that window. And a piece of luck that must not be booked as security: switching on the local SSH service needs admin rights, which the extension did not have on most Macs and Windows machines. There the step failed, and the attacker could not log in through the tunnel. The key was in anyway, the persistence too, and the machine data was on its way. Anyone who simply uninstalled the extension kept the key and the persistence. That is the point where most people stop, and exactly the point where it begins.
How to check, read-only
Cursor has published an official notice with clean-up steps, linked below, and that is the reference. What I show here is the first look, read-only, using only the indicators that are publicly confirmed. For macOS and Linux:
#!/bin/bash # Read only. Changes nothing. echo "[1] Foreign SSH key?" grep -n 'svc-telemetry' "$HOME/.ssh/authorized_keys" 2>/dev/null \ && echo "ALERT: key found" || echo "no known key" echo "[2] Tampered extension installed?" for d in "$HOME/.cursor/extensions" "$HOME/.vscode/extensions"; do [ -d "$d" ] && find "$d" -maxdepth 1 -iname 'anthropic.claude-code-2.1.313*' -print done echo "[3] Traces of the address in code or processes?" grep -rl '134\.209\.82\.225' "$HOME/.cursor/extensions" 2>/dev/null ps -axo pid,command | grep '134\.209\.82\.225' | grep -v grep echo "[4] Persistence: look at everything new since 29 Oct" ls -lat "$HOME/Library/LaunchAgents" 2>/dev/null | head crontab -l 2>/dev/null echo "done"
No hits is reassuring, but not proof. A hit means: machine off the network, delete nothing before you have preserved it, then Cursor's notice, then renew every credential this machine could reach. SSH keys, tokens, cloud access, sessions. Not just the ones whose names were in the beacon. All of them.
Finding is not enough. Remove and prove.
This is where I want to go beyond the usual security write-ups. Recognising that an extension was compromised is the smallest part. The work has three parts, and for us it now reads like this:
Find. Which extension, which process, which file behaves differently from yesterday? Not only known signatures. Behaviour: a code extension that writes to "authorized_keys", creates a background service or opens a connection to the outside has no business on a developer machine, whether or not its hash is already on some list.
Isolate and remove. Cut the connection, preserve the process, stop the persistence, then delete. In that order, because otherwise you delete the evidence along with it. And removing the extension is not enough: the keys, services and files it created live on without it.
Prove. Rescan after reboot, comparison against a known clean state, incident log, and the list of credentials that were renewed. Only when that exists is the machine a machine again.
What I am building from it: a Security Guard
After the 169 files I wrote that a guardrail at 95 percent is not one. Here is the next guardrail we did not have: nobody here was watching what the tools around the agents do. The agents, yes. The tools, no. So we are building that, as a service of its own in NeoCoder, and I describe it as a plan, not a product.
Integrity check. For every extension, every MCP server, every agent tool: version, hash, publisher, against what was there yesterday. An update that keeps the identifier and changes the hash is normal. One that additionally puts code in front of the known code is not.
Behaviour monitoring. Processes, network, SSH, persistence locations. Not "is this malware" but "did a development tool just behave like something else". The loader here should have stood out on four counts: writing to authorized_keys, outbound connection to a new address, new LaunchAgent, beacon without encryption.
Analysis. Rules first, deterministic. The model afterwards, for what the rules do not know, and it proposes, it does not decide.
Controlled clean-up. Known hash: block and isolate. Unexpected SSH key: cut access, preserve the key. Back channel: stop, freeze the process. Persistence: isolate, remove after approval. Possible token leak: revoke affected access. Unclear state: isolate the device, consider a rebuild. A small service with minimal rights executes the actions, from a fixed list. No model inventing shell commands.
Proof. Scan after reboot, comparison, log. The same discipline as with every finding in the workshop: not done because it is gone, done because it is documented.
The difference from a virus scanner is the second point. A virus scanner knows lists. We know how our tools normally behave, because we record everything that happens in the project anyway. An extension that suddenly writes to authorized_keys stands out by the deviation, not by the signature. And all of it runs locally, without cloud, because a security service that has to phone home before it can check has the same problem as the loader.
The limit you have to name
What is open
Above all, how the attacker was able to publish under the real publisher identifier in the Cursor Marketplace. Cursor says the version was not developed by Anthropic, and by its own account the exact path is still unclear. Whether the machine data was used anywhere further, nobody knows publicly. Nor whether all 5,000 removed the key again. The window was eleven hours. The consequences can last longer.
What remains
This incident shows no new weakness of language models. It shows how long the chain of trust has become that a developer machine hangs on: marketplace, publisher identifier, extension, editor, operating system, SSH, cloud access, company infrastructure. One link is enough. In the Binance piece I wrote that finding bugs has become easy. Here someone did not even need a bug. They pushed a file through the intended channel and waited for the auto-updates to fetch it.
The model was not hacked. The environment we hand our development rights to was. Finding is not enough, you have to remove and prove, and a compromised machine cannot deliver the proof itself. We are building a local Security Guard from this for the tools around the agents, one that knows behaviour instead of lists. And from now on, with every update, we check not only what an extension can do. But what it does at startup.
Sources
Cursor, security notice with clean-up steps. cursor.com/blog/claude-code-extension-security-notice. Number of affected users, time window, admin rights as the reason the SSH service failed.
OpenSourceMalware, technical analysis. opensourcemalware.com. 66-line loader, key name, address, beacon, collected data.
The Hacker News, 30 October 2026. thehackernews.com, including the correction that only the Cursor Marketplace was affected, not Open VSX.
Further reports. BleepingComputer, OX Security, Fast Company.
Status and caveat. 31 October 2026. The attackers' entry path has not been publicly clarified. The check script is a first, read-only look using the confirmed indicators; the full clean-up is in Cursor's notice. The Security Guard is a plan, not a finished product.
Written by me. The thoughts, the values, the learnings, the mistakes: all mine. Grammar and spelling are corrected by a twin model of my own, trained on my texts. Sometimes that turns into a mix. Of course I read everything again, but nobody is infallible. Whatever stays in is mine too.