Poisoned Pipeline / Incidents / AS340
The extension was Anthropic's; the build served from Cursor's marketplace was not
VS Code / IDEDeveloper workstationmacOS softwareWindows software
Cursor published a security notice on 29 October 2026 and StepSecurity,
Socket, OpenSourceMalware and Morphisec wrote it up the same day or the
next. A modified build of Anthropic's Claude Code extension,
Anthropic.claude-code, was served from the Cursor VS Code Extension
Marketplace for about eleven hours — 2:27am to 1:35pm Pacific, 09:27 to
20:35 UTC — and Cursor's notice names two versions, 2.1.312 and 2.1.313,
for macOS (darwin-arm64) and Windows (win32-x64), with a separate VSIX
hash for each. Cursor's estimate, carried by all three write-ups, is that
at most 5,000 users received it. Anthropic's own position, stated by Felix
Rieseberg and David Dworken, is that this was not a compromise of
Anthropic's systems or employee laptops: a malicious actor used access to
Cursor's marketplace to publish a tampered copy of an extension Anthropic
did not build or publish, the official channels were not affected, and
2.1.313 was never published to Open-VSX, the Microsoft Marketplace or any
Anthropic host. Anthropic skipped the number and shipped 2.1.314.
What differed from the real extension is one file. The manifest, the
bundled binary and the UI were the official build; extension.js carried a
self-contained 66-line immediately-invoked function prepended before the
legitimate bundle, which is roughly 7 KB on a 3,692,922-byte file
(SHA-256 ecb58cb29078d9646ad1dcdbe51526f2d9cfea06be5fb2ab183e8ecc3ab6bf15).
The injected stage imports only Node's process, fs, os, http and crypto
modules and touches no VS Code API, so loading the extension module is
enough: no Claude conversation, no workspace, no prompt. The package
declares no install, build, prepare, preinstall or postinstall script, so
nothing about the trigger resembles a package-manager lifecycle hook.
Nearly every exception inside the injected block is swallowed, which lets
the legitimate extension keep loading when a malicious step fails and
leaves the user with a working tool.
The chain is recon, access, tunnel, persistence, beacon. On load it reads
the hostname and username, the OS and CPU architecture, the home
directory and current working directory, and the global Git email from
git config --global user.email, and it enumerates the names of up to 40
environment variables containing KEY, TOKEN, SECRET, PASS, AWS or GCP.
Values are not placed in the beacon; the names alone say which cloud
providers, CI systems and credential types are configured on the machine.
It then creates ~/.ssh at mode 0700 and appends an Ed25519 key to
authorized_keys at 0600, commented svc-telemetry so it reads as an
administrative account, with fingerprint
SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk. It tries to make the
host reachable: systemsetup -setremotelogin on on macOS, systemctl
service checks and starts on Linux, and on Windows a PowerShell sequence
that installs the OpenSSH Server capability, sets it to automatic and
starts it. A base64 OpenSSH private key is decoded to a temporary file
named .stk_ followed by ten hex characters, and the loader connects
repeatedly as tunnel@134.209.82[.]225 with -N -R '*:0:localhost:22',
StrictHostKeyChecking=no, UserKnownHostsFile=/dev/null and
IdentitiesOnly=yes, preferring autossh and reconnecting about every 60
seconds. The embedded key's SHA-256 is
7e0a52885fadee05544a9e99eb18c792bec05900a5e1a66d68f8383decb0e278.
Persistence is written outside the extension so that removing it does not
remove the access. On macOS the loader drops ~/.config/.smt and .smtk and
a LaunchAgent at ~/Library/LaunchAgents/com.apple.sysmond.plist with
RunAtLoad and KeepAlive, loaded with launchctl load -w; the com.apple
prefix is decoration and the agent is not an Apple component. On Linux
the same scripts land under ~/.config and a @reboot entry goes into the
user's crontab. On Windows it writes .config\smt.cmd and smtk, tries to
create a scheduled task named SysMon running as SYSTEM at startup, and
falls back to copying sysmon.cmd into the user's Startup folder. After a
1.5-second delay it resolves the public IP through ifconfig.me and
api.ipify.org and POSTs the collected JSON to 127.0.0.1:8099/beacon and
then http://134.209.82[.]225:8099/beacon over plain HTTP, discarding
whatever comes back. No second stage is downloaded: the scripts and the
tunnel key are decoded from content already inside the extension.
Cursor removed the version, blocked further distribution, shut the
marketplace down entirely as a precaution, audited access and found no
other extension tampered with, rotated its keys and rebuilt the
marketplace. It worked with the hosting provider to take the attacker's
server offline on 30 October and published macOS and Windows remediation
scripts. Its assessment is that enabling the SSH service needs admin
rights the extension does not have on most hosts, so that step usually
failed and an attacker generally could not log in through the tunnel —
but the key, the persistence and the beacons still happened, and it warns
that the limited environment-variable collection does not rule out later
credential access over the backdoor. Morphisec adds that Kevin Beaumont
and researchers at Phorion were among the first to raise the alarm.
The distribution claim moved during the day and the catalogue records the
corrected version. OpenSourceMalware published first, on 29 October,
naming Open-VSX as the channel, and revised the article after Cursor
contacted them; the provenance of the directory it analysed was never
established, and its screenshot showing 2.1.313 as the latest release has
been withdrawn — Socket measured the Linux and Windows download sizes
visible in it against the public 2.1.314 builds and they match to two
decimal places. Socket's registry forensics found no publication or
removal event for 2.1.313 in Open-VSX's append-only change feed across
3,392 events from 27 October to 30 October 05:35 UTC: 2.1.312 and 2.1.314
appear with all eight platform builds each, and 42 versions across 21
other extensions were published and removed in the same window with both
events retained, one of them pulled about 90 seconds after publication.
The npm time map for @anthropic-ai/claude-code skips 2.1.313 between
2.1.312 at 18:36:10 on 27 October and 2.1.314 at 00:12:56 on 30 October,
and the public GitHub releases and changelog skip it too. Morphisec's
write-up still describes distribution through Open-VSX alongside the
Cursor marketplace; Anthropic's statement and Socket's check of the feed
are the reasons this story names Cursor's marketplace only.
StepSecurity verified the neighbours directly: the 2.1.312 build on
Open-VSX from 27 October and the 2.1.314 build from 30 October contain
none of the indicators, and 2.1.313 returns not found from both the
Open-VSX API and its content CDN. That is consistent with a marketplace
build that was tampered with rather than an official release that was
briefly published and withdrawn — and it means the version number was
never a reliable signal on its own, since Cursor's advisory lists a
malicious 2.1.312 for macOS and Windows as well.
Mapped techniques
- T0121 Compromised legitimate artifact
- T0154 Malicious IDE extension
- T0206 Forge or omit build provenance
- T0159 Malicious artifact execution
- T0134 Add user
- T0138 Backdoor in code
- T0172 Runtime backdoor
- T0193 Sensitive information in environment variables
supply-chain A tampered Claude Code build in Cursor's extension marketplace
The malicious build is the official extension in every respect
except extension.js, which has a 66-line injected function
prepended to the real bundle. Cursor's notice lists separate VSIX
hashes for 2.1.312 (darwin-arm64 fcbb327e…, win32-x64 3de17229…)
and 2.1.313 (darwin-arm64 80402fdc…, win32-x64 6786ec90…), so at
least two version numbers were repackaged. Consumers resolved the
real identifier and got bytes Anthropic did not build.
The delivered artifact is an IDE extension, but not a new listing
posing as a tool: it went out under Anthropic's own extension
identifier in a marketplace those users already trusted for this
extension. T0154 is written around an attacker uploading an
extension that looks like a legitimate add-on; here the extension
was legitimate and the build was not.
The repackaged build carried Anthropic's identifier, publisher
label and version lineage with nothing attesting who compiled it,
and 2.1.312 on Cursor's marketplace diverged from the clean 2.1.312
on Open-VSX. Marketplace publisher identity was the whole
provenance claim; the only integrity signal a consumer held was a
hash of bytes already received.
post-supply-chain Developers who received the build from Cursor's marketplace
The injected function runs when VS Code loads extension.js, before
the legitimate bundle initialises. It uses no VS Code API, so an
open conversation is not required, and the package declares no
install-time scripts, so nothing fires from the package manager.
An Ed25519 key is appended to ~/.ssh/authorized_keys with the
comment svc-telemetry, fingerprint
SHA256:0Z6R+DF64Do2nwQic8a7kkfDLNNk4IiK+2U2Rci4htk, and the SSH
service or Remote Login is switched on where the process has
rights. The catalogue's nearest technique is about creating an
account; this is an authorised-key insertion, the same durable
access with a lower footprint.
Persistence is dropped outside the extension — LaunchAgent
com.apple.sysmond.plist with RunAtLoad and KeepAlive, a crontab
@reboot entry, a SysMon scheduled task as SYSTEM or a Startup
folder script — so uninstalling the extension leaves the backdoor
running, which Cursor states explicitly.
A reverse SSH tunnel as tunnel@134.209.82[.]225 with
-N -R '*:0:localhost:22', an embedded private key, host-key
verification disabled and a 60-second retry. Cursor says the sshd
enablement usually failed for lack of admin rights, so the reachable
path depended on the host's privileges.
The beacon enumerates the names of up to 40 environment variables
matching KEY, TOKEN, SECRET, PASS, AWS or GCP alongside hostname,
user, OS, architecture, home and working directory, Git email and
public IP, and POSTs them in clear to the operator. Names only —
values stayed on the host — which maps to the reconnaissance half
of this technique rather than to secret theft.
Framework gaps noted
- How the build entered the marketplace is not publicly established. Cursor says a malicious actor "used access to Cursor's marketplace"; Anthropic says it did not build or publish the version; neither describes the account, the upload path or what review it passed. T0182 (bypass review using admin permission) would apply if elevated marketplace credentials were used, but nothing published supports that or any other specific route, so the catalogue records the artifact and not the way in.
- No host is reported compromised through the tunnel. Cursor's view is that enabling sshd needs admin rights the extension did not have, and no follow-on activity has been published, so the access capability is recorded and the impact is not. T0201 is deliberately unmapped.
- Auto-update, not user choice, delivered this to most affected people — they already had the extension and received a new build. No technique covers a first-party marketplace update channel pushing a tampered build to existing installs; T0220 is about a payload that becomes live only after review, and here the artifact was malicious as published.
- The payload contains Linux branches (systemctl service start, crontab @reboot) but Cursor's advisory lists only macOS darwin-arm64 and Windows win32-x64 hashes. No Linux VSIX hash was published, so the platform list here is the one Cursor confirms.
- StepSecurity's indicator table attributes fcbb327e… and 3de17229… to 2.1.313, while Cursor's notice lists those two under 2.1.312 and gives 80402fdc… and 6786ec90… for 2.1.313. The story follows Cursor, as the publisher of the advisory.
- Environment-variable names were collected; values were not sent in the beacon. T0193 describes secrets living in variables and is used here for the enumeration step, with the caveat that what left the host was a credential inventory rather than credentials.
- The Open-VSX claim is recorded as withdrawn rather than as a second channel — the screenshot could not be corroborated, the change feed has no event, and Morphisec repeated the claim without adding evidence. Nothing links this incident to the earlier IDE-extension and GlassWorm-shaped stories in the catalogue, and no actor is named.
Sources
- https://cursor.com/blog/claude-code-extension-security-notice
- https://www.stepsecurity.io/blog/claude-code-extension-trojanized
- https://socket.dev/blog/claude-code-extension-compromise
- https://opensourcemalware.com/blog/trojanized-claude-code-extension-plants-persistent-ssh-backdoor
- https://www.morphisec.com/blog/trusted-tool-malicious-build-what-the-trojanized-claude-code-extension-means-for-developer-endpoints/