BLOG
v 2.1.313 of the Cursor Marketplace Claude Code extension contains malware
By c0a15726-c5b1-4b0d-85e6-fe15553df9e2 ·
UPDATE: OpenSourceMalware has been contacted by Cursor and they've let us know that the Claude Code extension in the Cursor Marketplace experienced some form of compromise today and this is the origin of the malicious Claude Code extension, not Open VSX. Read Cursor's announcement about the incident HERE.
The official Claude Code extension in the Cursor marketplace was compromised today. Yes, you heard that right.
A malicious version, 2.1.313 was published to the Cursor Marketplace, today, October 29th, 2026. The extension identifies itself as anthropic.claude-code version 2.1.313, but its main JavaScript bundle contains a malicious 66-line loader inserted before the legitimate extension code.
What is malicious:
Claude-code extension from Cursor marketplace version 2.1.313 (threat report here)
What is not malicious:
The @anthropic-ai/claude-code NPM package is NOT malicious
The Open VSX extension is NOT malicious
The Microsoft VS Code extension for Claude is NOT malicious
TL;DR
Threat Type: Trojanized developer-tool extension and persistent SSH backdoor
Affected Ecosystem: Cursor Marketplace
Claimed Package:
anthropic.claude-code@2.1.313Impact: Persistent remote access through an authorized SSH key and reverse SSH tunnel
C2:
134.209.82.225over SSH and HTTP port 8099Key Finding: Malicious code is prepended to the normal extension bundle and executes before legitimate initialization
Additional Payloads: None downloaded by the injected stage; its
curlrequests retrieve only public-IP text
What does it do?
The unpacked extension is exactly like the normal version, and the bundled binary is the official binary as well. The only thing that's different is the extension.js file.
The extension activates after VS Code startup and when its webview opens and runs the extension.js file. It adds an attacker-controlled key to the user’s SSH configuration, attempts to enable the local SSH service, establishes a reverse tunnel to 134.209.82.225, installs platform-specific persistence, and transmits host reconnaissance over an unencrypted HTTP beacon.
Technical Analysis
Big shout out to Dean Hardcastle for looping us in when he saw this happen in real time.
The OpenSourceMalware team got access to the original malware artefacts. We were told that initial infection was the Claude Code Open VSX extension, and that victims were compromised during a auto-update of the extension. Sure enough, when we examined the files, that's exactly what we found: a Claude Code VSCode extension. It had all the standard files and structure that a VSCode extension would have. A README.md file and a package.json package manifest. The package.json file was clearly for the Claude Code VS Code extension, and the name was "claude-code" and marked its version as 2.1.313.
{
"name": "claude-code",
"displayName": "Claude Code for VS Code",
"description": "Claude Code for VS Code: Harness the power of Claude Code without leaving your IDE",
"version": "2.1.313",
"publisher": "Anthropic",
"license": "© Anthropic PBC. All rights reserved. Use is subject to the Legal Agreements outlined here: https://code.claude.com/docs/en/legal-and-compliance.",
"bugs": {
"url": "https://github.com/anthropics/claude-code/issues",
"email": "support@anthropic.com"
},
"engines": {
"vscode": "^1.94.0"
},Static inspection of the main entry point quickly paints a picture: The first line starts a standalone, immediately invoked function that imports Node.js process, filesystem, operating-system, HTTP, and cryptographic modules. That function ends at line 66. Only after it finishes does the expected bundled extension begin. This placement matters: the user doesn't need to begin a Claude conversation. Loading the extension module is enough. The package declares no install, build, prepare, preinstall, or postinstall scripts, so the malicious behavior occurs at extension runtime rather than through a package-manager lifecycle hook.
The first section of the malicious JavaScript payload doesn't make any attempt to hide what its doing and it uses no obfuscation. The first ten lines clearly show that it exfiltrates sensitive data and sets up a SSH based reverse shell. Most mature detections would pick up both the exfil and the reverse shell. Then on line 69, it appended a heavily obfuscated second JavaScript section.
At this point, we were fairly certain that we were dealing with a malicious version of the Open VSX Claude Code extension, and we knew it was version 2.1.313. The first thing to do is to compare it against the last version from Open VSX which was version 2.1.312 released just a few days before. We downloaded the same Mac ARM version of the package but for version 2.1.312 and compared the files:
The two sets of files were almost identical except for the package.json and the extension.js files and the 2.1.313 version also has a .vsixmanifest file:
The .vsixmanifest file was named differently, and it was in a different location than the equivalent file that's in the 2.1.312 version, which is typically "extension.vsixmanifest". Otherwise its format was standard and the only content difference between the two was the new version number "2.1.313":
<?xml version="1.0" encoding="utf-8"?>
<PackageManifest Version="2.0.0" xmlns="http://schemas.microsoft.com/developer/vsx-schema/2011" xmlns:d="http://schemas.microsoft.com/developer/vsx-schema-design/2011">
<Metadata>
<Identity Language="en-US" Id="claude-code" Version="2.1.313" Publisher="Anthropic" TargetPlatform="darwin-arm64"/>
<DisplayName>Claude Code for VS Code</DisplayName>
<Description xml:space="preserve">Claude Code for VS Code: Harness the power of Claude Code without leaving your IDE</Description>
<Tags>claude,sonnet,ai,mcp,agent,keybindings,json</Tags>
<Categories>AI,Chat</Categories>
<GalleryFlags>Public</GalleryFlags>
<Properties>
<Property Id="Microsoft.VisualStudio.Code.Engine" Value="^1.94.0" />
<Property Id="Microsoft.VisualStudio.Code.ExtensionDependencies" Value="" />
<Property Id="Microsoft.VisualStudio.Code.ExtensionPack" Value="" />
<Property Id="Microsoft.VisualStudio.Code.ExtensionKind" Value="workspace" />
<Property Id="Microsoft.VisualStudio.Code.LocalizedLanguages" Value="" />
<Property Id="Microsoft.VisualStudio.Code.EnabledApiProposals" Value="" />
<Property Id="Microsoft.VisualStudio.Code.ExecutesCode" Value="true" />
<Property Id="Microsoft.VisualStudio.Services.Links.Support" Value="https://github.com/anthropics/claude-code/issues" />
<Property Id="Microsoft.VisualStudio.Services.GitHubFlavoredMarkdown" Value="true" />
<Property Id="Microsoft.VisualStudio.Services.Content.Pricing" Value="Free"/>
</Properties>
<Icon>extension/resources/claude-logo.png</Icon>
</Metadata>
<Installation>
<InstallationTarget Id="Microsoft.VisualStudio.Code"/>
</Installation>
<Dependencies/>
<Assets>
<Asset Type="Microsoft.VisualStudio.Code.Manifest" Path="extension/package.json" Addressable="true" />
<Asset Type="Microsoft.VisualStudio.Services.Content.Details" Path="extension/README.md" Addressable="true" />
<Asset Type="Microsoft.VisualStudio.Services.Icons.Default" Path="extension/resources/claude-logo.png" Addressable="true" />
</Assets>
</PackageManifest>Assuming this was an Open VSX extension, the OSM team checked Open-vsx.org and we noticed that the current version of the Claude Code extension was 2.1.314 and that version 2.1.313 was missing. At this point, we started operating under the impression that Open VSX might have removed the 2.1.313 version because it was malicious. That theory was further validated when we checked the Claude Code NPM package and realized there was no version 2.1.313 available. It was the same pattern as the Open VSX extension: it jumped from version 2.1.312 to 2.1.314. Same thing with the Claude Code extension in the VS Code Marketplace: No version 2.1.313, and it jumped straight to 2.1.314.
At this point, it made sense that that if version 2.1.313 of the Claude Code release is malicious, it would be removed from all these registries. It's pretty standard practice for NPM, PyPI and other registries to remove versions of packages when they're flagged as malicious, and that's what we assumed was happening here.
UPDATE: The malicious extension did not originate with Open VSX and instead was from Cursor's mirror of the Open VSX registry
Is the official Open VSX registry affected?
The simple answer is no.
It turns out that Cursor manages a complex internal service that pulls packages from Open VSX. Its like a mirror, but its also more than that as Cursor manages a set of their own extensions as well. Based on what extension the user has asked for, or that needs updating, the internal service decides where to pull the new file from and then gets it from Open VSX or the internal system. These files are served via a Cursor CDN hosted in Cloudflare.
Cursor Marketplace has been compromised
So, the malicious Claude Code extension originated from Cursor's Marketplace, not Open VSX.
The next question is: How was an attacker able to get a malicious extension into Cursor's marketplace AND trick Cursor's internal service into serving up a version 2.1.313 that wasn't in Open VSX?
The Cursor security team reached out to OpenSourceMalware and confirmed that their Cursor marketplace was compromised. However, they didn't share how it happened. OSM has reached out to their team multiple times asking for updates, but so far they have not responded. Our understanding from that meeting is that this compromise was larger than just the single Claude Code extension. This was corroborated by the fact that Cursor took their whole marketplace offline for a period of time so they could rebuild it.
This sends a clear message that this wasn't about one malicious extension. You don't rebuild a whole service unless there is a deeper problem.
Cursor has updated their "advisory" to now say that there were TWO malicious versions of the Claude Code extension in their marketplace: 2.1.312 and 2.1.313. You can read their advisory HERE.
The Claude Code extension is still not available in the Cursor marketplace, and the OSM team wonders, will it return? This hack makes Anthropic look bad, but the reality is that a threat actor was able to publish an official Anthropic branded Claude Code extension to the Cursor marketplace.
A package registry or marketplace that distributes software under someone else's publisher identity inherits the responsibility to authenticate that publisher. A manifest claiming to be Anthropic is not equivalent to a release authorized by Anthropic. This begs the question: Who is allowed to publish as Anthropic?
More to come on this soon....
What does the malware do?
At load time, the implant collects:
Hostname and local username
Operating system and CPU architecture
Home directory and current working directory
Global Git email from
git config --global user.emailNames of up to 40 environment variables containing
KEY,TOKEN,SECRET,PASS,AWS, orGCP
Environment-variable values are not placed directly in the initial beacon. Their names can still reveal which cloud providers, CI systems, and credential types are configured. More importantly, successful SSH access would allow the operator to inspect the account directly.
Nearly every exception is suppressed. This lets the legitimate extension continue loading when malicious operations fail, reducing visible signs of compromise.
If a home directory is available, the implant creates ~/.ssh, changes it to mode 0700, and appends an Ed25519 key to ~/.ssh/authorized_keys. The key is labeled svc-telemetry, an innocuous-looking comment intended to resemble an administrative account.
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIDdvylCEJ/k2TpezcTfedrkHyFSK9IZ3vmP6vhY4Ss0P svc-telemetry
Its fingerprint is:
SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk
The implant sets authorized_keys to mode 0600. If the marker already exists, it records that fact instead of adding a duplicate.
SSH service enablement
The next branch attempts to make the victim reachable through SSH:
macOS: checks Remote Login and, if disabled, runs
sudo -n systemsetup -setremotelogin onLinux: checks
sshdorsshwithsystemctl, then tries several service-start commandsWindows: uses PowerShell to install OpenSSH Server, configure automatic startup, and start
sshd
These operations may fail without sufficient privileges, but failure does not stop the remaining attack chain.
Reverse SSH tunnel
The implant embeds a base64-encoded OpenSSH private key and decodes it into a temporary file named .stk_<identifier>. The identifier derives from the hostname and home directory. The decoded private key has SHA-256:
7e0a52885fadee05544a9e99eb18c792bec05900a5e1a66d68f8383decb0e278
It repeatedly connects to:
tunnel@134.209.82[.]225
The core forwarding request is:
-N -R '*:0:localhost:22'
This asks the remote SSH server to allocate a port and forward connections through the tunnel to port 22 on the victim. Whether that port is reachable beyond the C2 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.
Platform-specific persistence
The loader implements three platform branches.
On macOS it writes:
~/.config/.smt
~/.config/.smtk
~/Library/LaunchAgents/com.apple.sysmond.plist
.smt reconstructs the private key and continuously launches the tunnel. The LaunchAgent uses RunAtLoad and KeepAlive, then loads with launchctl load -w. The com.apple.sysmond name is deceptive; this user LaunchAgent is not an Apple component.
On Linux, the same files are written under ~/.config, and the script is added to the user’s crontab with an @reboot entry.
On Windows, the malware writes .config\smt.cmd and .config\smtk, then attempts 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.
Reconnaissance beacon
After 1.5 seconds, the malware obtains the public IP using:
curl -s --max-time 4 ifconfig.me
curl -s --max-time 4 https://api.ipify.org
It sends the collected JSON to:
http://127.0.0.1:8099/beacon
http://134.209.82.225:8099/beacon
The response is discarded. There is no response-to-code behavior in the injected stage, and returned data is not saved as a payload or configuration.
Does It Download More Malware?
No additional executable or script is downloaded by the injected loader. Its network behaviour consists of public-IP text lookups, JSON beacon uploads, and an interactive SSH tunnel.
The shell and batch scripts and tunnel keys are generated or decoded from content already inside the extension. They are not secondary downloads. That distinction does not reduce the severity: the tunnel provides an operator-controlled route to the victim’s SSH service. Follow-on commands or files transferred after access would not appear in this static artifact.
No blockchain addresses, RPC endpoints, contracts, wallets, or blockchain-resolved payload locations were found.
Attack Chain
Stage
Trigger
Behavior
Outcome
Execution
VS Code loads extension.js
Prepended IIFE runs before legitimate code
Confirmed
Access
Home directory exists
Adds svc-telemetry authorized key
Confirmed
Service setup
Platform branch
Attempts to enable SSH or Remote Login
Conditional on OS and privileges
Tunnel
No matching Unix tunnel
Drops embedded key and launches reverse SSH loop
Confirmed code path
Persistence
Platform branch
LaunchAgent, cron, scheduled task, or Startup item
Conditional on OS
Reconnaissance
1.5-second timer
Queries public IP and sends two beacons
Confirmed
C2 response
Beacon completes
Response drained and ignored
No execution path
Additional download
Any injected path
No downloader identified
None
Indicators of Compromise (IOCs)
Package Identity
anthropic.claude-code@2.1.313Network Indicators
134.209.82.225
134.209.82.225:22
http://134.209.82.225:8099/beacon
http://127.0.0.1:8099/beacon
ifconfig.me
https://api.ipify.org
SSH Indicators
tunnel@134.209.82.225
svc-telemetry
SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk
Files and Persistence
~/.config/.smt
~/.config/.smtk
~/Library/LaunchAgents/com.apple.sysmond.plist
${TMPDIR}/.stk_*
~/.config/smt.cmd
~/.config/smtk
SysMon
sysmon.cmd
File Hashes (SHA-256)
extension.js
ecb58cb29078d9646ad1dcdbe51526f2d9cfea06be5fb2ab183e8ecc3ab6bf15
embedded tunnel private key
7e0a52885fadee05544a9e99eb18c792bec05900a5e1a66d68f8383decb0e278
deterministic aggregate digest of analyzed directory
18756b75afedee74bbf49832a1b1dada4961672c41d595be5c1bbe75709de927
Detection and Response
Search endpoints for the file paths, SSH key comment, LaunchAgent label, task name, IP address, and hashes above. On macOS, inspect loaded LaunchAgents and each user’s authorized_keys. Process telemetry may show long-running ssh or autossh commands containing -R *:0:localhost:22.
If the artifact was loaded, disconnect the system, preserve forensic evidence, and block 134.209.82.225 on ports 22 and 8099. Remove the extension and persistence only after collecting evidence. Rotate credentials accessible to the affected account from a known-clean system.
Because this implant creates an interactive path to SSH, its 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 removal of known artifacts restores trust.
Conclusion
This sample demonstrates an effective way to weaponize a trusted developer tool: place a compact backdoor before a large legitimate bundle, suppress errors, and let the expected application continue. The extension retains its normal interface while quietly establishing durable SSH access.
The evidence supports conclusions about the analyzed artifact only. Distribution source, attacker identity, infrastructure ownership, and the status of any official release remain unverified and should not be inferred from package branding.