PatchDay Alert
Analysis · 8 min read · 1,694 words By Colten Anderson · Commentary

GlassWorm's botnet is down, but the technique it proved still works

CrowdStrike, Google, and Shadowserver knocked out all four C2 channels at once. That ends the infrastructure, not the playbook. Three primitives outlive the takedown.

GlassWorm's botnet is down, but the technique it proved still works

A reviewer reading the poisoned extension in VS Code, in a GitHub diff, or through git diff saw nothing wrong. The malicious JavaScript was right there in the source the whole time, encoded in Unicode characters that render to zero width. The payload was never hidden by obfuscation, the way malware usually hides. It was hidden in plain text, by exploiting the fact that human review and almost every static tool assume the bytes they cannot see are not there.

On May 26, 2026, CrowdStrike, Google, and the Shadowserver Foundation took down all four GlassWorm command-and-control channels at once and sinkholed the surviving bots. The coverage read the way these things usually read: a resilient botnet, finally killed. That is true and it is worth noting. It also misses what GlassWorm actually was.

The obvious read

The conventional take is straightforward. GlassWorm built an unusually durable C2, defenders spent months unable to delete it, and a coordinated action finally severed it. Threat closed, risk down a notch. If you set patch and risk priority for a team, the natural move is to file this under “handled” and let IDE-extension supply-chain risk drift back down the list.

That move is a mistake. The takedown removed the operator’s live control. It did not remove a single line of already-pushed malicious code, rotate one stolen token, or change anything about why the attack worked in the first place. More to the point, GlassWorm was never really one botnet. It was a working demonstration of three reusable primitives, and a C2 takedown does not retire any of them.

The pattern: three primitives, not one botnet

Look at GlassWorm as a template rather than a campaign and three distinct capabilities separate out, each independently reusable.

The first is invisible code that defeats review. The carrier set, per the open-source scan-unicode-attacks tool and Koi Security’s original writeup, is Unicode Variation Selectors (U+FE00–U+FE0F) and the Variation Selectors Supplement (U+E0100–U+E01EF). That is 256 invisible code points that map one-to-one onto byte values, so an attacker can smuggle an arbitrary byte stream through anything that treats them as decoration. A small visible decoder stub reconstructs the bytes and runs them through eval(). Grep, linters, human eyes: all blind to it unless they are specifically told to flag non-printing, non-ASCII characters. This primitive has nothing to do with VS Code. It works anywhere code is reviewed as text, which is everywhere.

Un-deletable C2 backed by public infrastructure. The primary channel used the Solana blockchain as a dead-drop resolver. A wallet address is hardcoded into the payload; the malware reads the memo field of that wallet’s transactions to find the next-stage URL. Because Solana transactions are immutable and public, as The Register laid out, defenders cannot delete the pointer. Only the operator can post a newer one. Fallbacks layered on Google Calendar event titles, the BitTorrent DHT, and ordinary VPS servers. This is exactly why the takedown had to hit all four channels simultaneously: knock out a subset and the operator reconstitutes through whatever survived. The architecture is the lesson, and the architecture is copyable. The next campaign points at a different wallet.

The third primitive is credential-mediated self-propagation. The malware harvests the victim’s publishing credentials and uses them to push freshly poisoned versions under that developer’s trusted identity. Each compromise becomes the launch point for the next. In a later wave, The Hacker News reported, the same loop extended to GitHub: stolen tokens force-pushed malicious commits rebased on top of legitimate ones, preserving the original author, timestamp, and message so no pull request or notification trail appeared. StepSecurity tracked that variant as “ForceMemo” across hundreds of Python repositories. Stealing a token and republishing as a trusted author does not require any specific C2 to be alive.

None of these three needs the others. The botnet was the thing that got taken down. The primitives are the thing that got proven, and proven techniques get reused.

The evidence the loop already survived once

The strongest argument that infrastructure removal does not close GlassWorm is that containment already failed once, on its own timeline, with no help from a takedown.

The Eclipse Foundation, which runs OpenVSX, declared the initial incident contained on October 21, 2025. About two weeks later, on November 6, Koi found three more infected extensionsai-driven-dev.ai-driven-dev, adhamu.history-in-sublime-merge, and yasuyuky.transient-emacs. Through early 2026, Socket documented “sleeper” extensions that shipped benign, passed review, and were weaponized by a later update. A “contained” declaration did not hold for a fortnight against an attack built on credential reuse and trusted-author republishing. A C2 takedown is a different and bigger action, but it operates on the same campaign whose propagation loop already demonstrated it does not need any single piece of infrastructure to stay alive.

The channel matters here. GlassWorm surfaced on OpenVSX, the community registry that VS Code forks depend on because they cannot use Microsoft’s proprietary marketplace. That is why Cursor, Windsurf, VSCodium, and Positron were all in scope from the same poisoned packages, and at least one infected extension also reached Microsoft’s official marketplace before removal. The first flagged extension, codejoy.codejoy-vscode-extension, was caught on October 17, 2025. The registry trust model — extensions are unsigned, auto-updating code running at full developer privilege with no sandbox — is the actual gap, and the takedown left it untouched.

A note on the numbers, because precision is the price of trust here. Koi reported roughly 35,800 downloads across affected extensions; the Eclipse Foundation disputed that, saying bots and ranking-inflation tactics drove a meaningful share and the real install count was materially lower. Neither side published an audited alternative, so treat 35,800 as “downloads Koi observed,” not “machines infected.” It is worth flagging too that nearly all the deep technical detail traces to Koi, a relatively small vendor, repeated rather than independently reverse-engineered at the same depth. CrowdStrike’s takedown analysis is the strongest independent corroboration, and it confirms the C2 infrastructure more than the payload internals. The disagreement itself is informative: when the registry operator and the reporting vendor cannot agree on scale, the responsible read is to plan around the technique, which is not in dispute, rather than the count, which is.

Even the name is contested. Koi called it the first self-propagating worm in the extension ecosystem; Eclipse’s Mikaël Barbero argued it “was not a self-replicating worm in the traditional sense” because it spreads through stolen credentials rather than autonomously. Both descriptions of the mechanism are accurate. The taxonomy is unresolved and, for prioritization, beside the point. Worm or credential-theft loop, the November re-emergence settled the only question that matters operationally: the propagation loop was not severed by declaring it severed.

What this means for prioritization

The registry trust model is the standing exposure, and it sits above this specific campaign. Unsigned, auto-updating, full-privilege code with no sandbox is the gap that made GlassWorm possible and will make the next one possible too. A takedown reaches the operator’s live control; it does not reach the conditions that let a poisoned extension run in the first place. If you own the patch and risk queue, that is the line item that should not move down your list on the strength of a botnet obituary. The sleeper pattern is the reason it stays high: an extension that ships benign and turns malicious on a later update defeats a one-time review, so the exposure is continuous rather than a single bad package you can find and delete.

The credential exposure is the other thing the takedown did not touch. Tokens read from secret storage do not un-leak when a C2 goes dark, and anyone who ran an affected extension is best understood as an active credential incident rather than a closed one. GitHub PATs, npm tokens, OpenVSX credentials, and SSH keys are still in whoever’s hands harvested them, regardless of whether the channel that exfiltrated them is now sinkholed. What changed on May 26 is that the live operator lost a control channel. What did not change is the exposure surface or the techniques that created it, and prioritization should track the second, not the first.

What to watch

The pattern is confirmed if the invisible-Unicode carrier or blockchain dead-drop shows up under a different name and a different operator, decoupled from GlassWorm’s now-dead infrastructure. It is partly disproven if registry operators ship the controls that actually close the door, shorter token lifetimes and pre-publication scanning that catches the decoder pattern before it publishes. The Eclipse Foundation announced both; whether they shipped on the stated early-2026 timeline is not confirmed in the public record. Attribution stays where CrowdStrike left it, likely Russia-based, no conclusive evidence, and the financial motive (credential theft, wallet draining, proxy access) makes reuse by unrelated crews more likely, not less. Profitable techniques do not stay proprietary.

The headline says a resilient botnet died. The more durable fact is that someone published a working recipe for code that survives review, C2 that survives deletion, and propagation that turns every victim into a distributor. PatchDay Alert tracks the technique that gets reused, not just the campaign that made the news, so when the next invisible-code package lands on a registry your developers trust, you will read about the pattern before you read about the count.

Sources

Share

Related field notes

Get the free CVE triage cheat sheet

Subscribe and we'll email you the one-page triage flow for fresh CVEs. Plus the weekday digest.

Subscribe