psf-claude-code-vsx-oct2026-check(8)

Script: /opt/psf-security-patches/claude-code-vsx/claude-code-vsx-oct2026-check.sh. Tool page: Claude Code extension backdoor. Source. With the package installed: man psf-claude-code-vsx-oct2026-check.

Claude Code extension SSH backdoor (Cursor marketplace, 29 October 2026): check, hunt, update, keys, clean  (v1)
No CVE (supply-chain compromise of an editor extension)

If this software is helpful, consider a donation to our 501c3 nonprofit:
https://privacysafe.foundation

Cursor reports that between about 2:27am and 1:35pm Pacific time on 29 October
2026 a maliciously modified copy of the Claude Code extension for VS Code
(versions 2.1.312 and 2.1.313) was served from the Cursor extension
marketplace, to up to 5,000 developer machines. Anthropic says it was not
involved in building, publishing or hosting the tampered build. A prefix added
to extension.js runs the moment the editor loads the extension. It:
  - appends the attacker's ed25519 key (comment "svc-telemetry") to
    ~/.ssh/authorized_keys;
  - writes ~/.config/.smt (a retry loop) and ~/.config/.smtk (the tunnel key),
    and a copy of the tunnel key as .stk_<10 hex> in the temp directory;
  - opens a reverse SSH tunnel (ssh -N -R '*:0:localhost:22') to
    tunnel@134.209.82.225 and retries it about every 60 seconds, kept alive
    across reboots by a LaunchAgent (~/Library/LaunchAgents/
    com.apple.sysmond.plist) on macOS or an @reboot crontab entry on GNU/Linux
    (a scheduled task named SysMon on Windows);
  - tries to switch the local SSH server on (this fails without admin rights
    on most machines, so the inbound path is often closed, but the key and
    the persistence are still planted);
  - POSTs the hostname, user name, OS, public IP, git email and the NAMES of
    environment variables that look like secrets (not their values) to
    http://134.209.82.225:8099/beacon.
Cursor says it has had the attacker's server taken offline. Treat that as a
reason the damage may be smaller, not as a reason to skip the cleanup.

Updating or uninstalling the extension does NOT remove any of that. A
replacement build, 2.1.314, was published on 30 October; it swaps the
extension's files and leaves the key, the scripts and the persistence in
place. This script checks for each piece separately.

One detail matters when judging versions: a legitimate 2.1.312 exists (it is
on npm and Open VSX, published 27 October). Only the copy served by Cursor's
marketplace was modified. So 2.1.312 is judged by the content of its
extension.js, not by its number. 2.1.313 was never published legitimately
anywhere and is reported on sight.

Get the vendor's fix FIRST, then clean. Anthropic replaced the bad build with
Claude Code 2.1.314 (published 30 October 2026); 2.1.314 or newer is the fix. Every
run of check, hunt, clean and update says so up front. The "update" command below
installs it through your editor, but only after it shows you the state of the
machine and asks. Installing the fix is half of the job: it does not remove an
SSH key, implant files or persistence that already got planted.

Usage:
  ./claude-code-vsx-oct2026-check.sh [command] [options]

  check (default)  read-only. Looks for: an installed Claude Code extension
                   that is 2.1.313 or carries the backdoored extension.js
                   (known SHA-256, the C2 address or the svc-telemetry key
                   comment); a downloaded or cached extension package with a
                   known bad hash; the attacker's key in authorized_keys
                   (matched by key, by fingerprint and by comment), with an
                   inventory of every other key so an unknown one stands out;
                   the implant files; the crontab entry or LaunchAgent;
                   running tunnel processes; a connection to the C2; and
                   whether this machine's SSH server is reachable on the
                   loopback address, which is the door the tunnel opens.
                   Exit 0 = nothing found, 1 = exposure or compromise found,
                   2 = could not read what it needed to.
  hunt             read-only. Searches the SSH server logs for a login with
                   the attacker's key (a login through the tunnel arrives
                   from 127.0.0.1 or ::1), and lists recent changes under
                   ~/.ssh, ~/.config and the LaunchAgents folder for review.
                   Exit 0 = no login evidence, 1 = evidence found.
  update           the vendor's fix, with questions first. (1) a read-only check, as
                   above. (2) for each editor command line (code, cursor, codium,
                   windsurf) whose extensions folder holds Claude Code, it shows the
                   command it would run (<editor> --install-extension
                   anthropic.claude-code --force; the editor downloads the extension
                   from its own marketplace, this script downloads nothing) and asks
                   before running it. An editor that does not have the extension is
                   not offered one. (3) it checks again, says whether Claude Code
                   2.1.314 or newer is now installed, and, if the machine shows the
                   backdoor, asks whether to run 'clean' now. It needs a terminal to
                   ask on, or --yes (install without asking). --yes never answers the
                   clean question: that needs an answer at the terminal, or --and-clean. As root it checks and cleans but does not
                   install, because editors are per user. Close the editor first.
                   --dry-run shows the commands and runs none.
  keys             read-only. Lists the private keys in each account's ~/.ssh with
                   their type, fingerprint, last change and whether a passphrase
                   protects the file, and counts the agent sockets in ~/.ssh/agent.
                   It prints no key material. A private key file that no passphrase
                   protects can be used by anything that can read it, which is what
                   a file-reading flaw in an editor or assistant gets; keys loaded in
                   an ssh-agent are not in those files. OpenSSH 10.1 and later keep
                   the agent's socket in ~/.ssh/agent (older versions use /tmp):
                   that folder holds sockets, not keys, so there is nothing in it to
                   block. Exit 0, or 2 if something could not be read.
  clean            containment and cleanup. Stops the tunnel processes,
                   unloads and removes the persistence, removes the
                   attacker's key line from authorized_keys, and moves the
                   implant files and the bad extension folders into a
                   backup folder (nothing is deleted). Add --reinstall to
                   install the extension again through any editor command
                   line it finds (code, cursor, codium, windsurf). Close the
                   editor first. Re-checks afterwards and exits 1 if anything
                   remains. --dry-run shows what it would do. Before it changes anything
                   it keeps a record of each account's ~/.ssh in the backup folder:
                   authorized_keys, config and known_hosts with their times, an
                   inventory of the private keys (no key material), and the names of
                   the agent sockets. --copy-keys also copies the private key files
                   into the backup folder (0600), which is one more copy of a secret:
                   delete it once you have rotated the keys. --drop-agent-keys empties
                   the ssh-agents that belong to you (ssh-add -D) after the record is
                   kept; the keys must be added again afterwards. It is not a cure:
                   it does not help against key files that were already copied.
  block            GNU/Linux, as root: drop outbound traffic to the C2
                   address with nftables or iptables. Defense in depth only;
                   rules do not survive a reboot. On macOS it prints how to
                   do the same. --dry-run shows the command.
  unblock          remove the rule that block added.
  version          print the script version.

Options: --dry-run (clean, block, unblock, update)   --reinstall (clean)   --yes, --and-clean (update)
         --copy-keys, --drop-agent-keys (clean, and the clean step of update)

Run it as your own user to check your own account. Run it as root to check
every account on the machine. It works on GNU/Linux and macOS. Windows has its own
check, claude-code-vsx-oct2026-check.ps1 in this folder (PowerShell, read only).

Env overrides:
  NO_NOTICE=1                       leave out the upfront notice about the vendor's fix
  ANSWERS_FILE=/path                answers for update, one per line (y or n), read
                                    instead of the terminal (for automation)
  HOMES="/home/a:/home/b"           accounts to check, colon separated (default:
                                    you; as root: every account)
  BACKUP_ROOT=/var/backups/claude-code-vsx-oct2026   where clean puts files
                                    (default for a normal user:
                                    ~/claude-code-vsx-oct2026-backup)
  TMP_DIRS="/tmp:/var/tmp"          where to look for .stk_ key copies (colon separated)
  EXT_ROOTS_EXTRA="/opt/ide/extensions"   more folders that hold extensions (colon separated)
  EXTRA_KEY_BLOBS, EXTRA_FPRS, EXTRA_SHA256   more indicators, space separated,
                                    for when the vendors publish updates
  HUNT_LOGS="/var/log/ssh/*.log"    extra log files for hunt
  HUNT_LOG_DAYS=4                   how many days of macOS log to search
  LOOPBACK_PORT=22                  port to probe on 127.0.0.1
  PLATFORM=Linux|Darwin             override the detected platform
     PSF_LOCK_WAIT    seconds a run that changes the host waits for another one that is already
                      changing it (default 30), then stops with exit 2; the lock is STATE_DIR/.lock

The Security Patches software and this documentation are dedicated to the public domain under CC0 1.0 Universal. Other pages on privacysafe.app/docs are CC BY-SA 4.0 unless the page says otherwise.

The PrivacySafe Ecosystem

Shop at Ivy Cyber

Ivy Cyber offers PrivacySafe products and services in the USA and has partnerships with 3NSoft in Canada and Kuip Limited in the European Union. Enterprise services and consulting are available at ivycyber.com

PrivacySafe Foundation is a 501(c)(3) nonprofit public charity that supports the development of the PrivacySafe applications, along with the components they rely upon: 3NWeb protocols, filesystem, documentation, and reference implementations.

PrivacySafe Foundation

Donations to PrivacySafe Foundation support education, research, documentation, and public code. Purchases from Ivy Cyber support PrivacySafe products, services, hosting, and technical support. Together, we're building a better web.