analyst @ nohacky :~/briefings $
cat / briefings / glassworm-forcememo
analyst@nohacky:~/briefings/glassworm-forcememo-github-python-supply-chain.html
reading mode 10 min read
category supply chain
published March 19, 2026
read_time 10 min
threat_actor GlassWorm
campaign ForceMemo

GlassWorm's ForceMemo Campaign Is Poisoning Python Repos Through Stolen GitHub Tokens

An active and expanding supply chain campaign is silently rewriting the git history of hundreds of Python repositories using credentials stolen months earlier through malicious VS Code extensions. The attack leaves almost no visible trace and is still spreading as of this writing.

If your team pulls Python packages directly from GitHub, runs pip install from source repositories, or uses VS Code or Cursor with third-party extensions, there is an ongoing threat you need to understand right now. The GlassWorm threat actor, active since October 2025, has evolved its operation into a new campaign that researchers at StepSecurity named ForceMemo after its two defining technical signatures: the use of Git's force-push command to silently overwrite repository history, and the use of Solana blockchain transaction memos as a command-and-control channel that cannot be taken down.

The earliest confirmed ForceMemo infections date to March 8, 2026. The campaign was publicly identified and named by the StepSecurity threat intelligence team on March 14, 2026. As of the date of this article, it remains active. Researchers at Aikido Security, Socket, Sonatype, and BleepingComputer have all independently corroborated the findings and identified overlapping infrastructure tying this campaign to a long-running and increasingly sophisticated threat actor.

Who Is GlassWorm and Where Did It Come From

GlassWorm is not new. Researchers at Koi Security first documented the threat actor in October 2025, when seven extensions on the OpenVSX marketplace were compromised on a single day. Those extensions had a combined download count of approximately 35,800. What made GlassWorm historically notable was the technique it used to hide its payload: invisible Unicode characters, specifically Unicode variation selectors and Private Use Area characters, were used to embed executable JavaScript code in files that appeared completely blank to any developer reading the source in a code editor.

This rendered conventional code review useless. A developer could stare at the infected file and see nothing wrong. The malware was not minified. It was not obfuscated in any traditional sense. It was literally invisible to the human eye.

"Seven OpenVSX extensions were compromised on October 17, 2025, with 35,800 total downloads, and ten extensions were still actively distributing malware two days later." — Truesec Security Research, December 2025

Beyond stealth, GlassWorm was designed with self-propagation in mind. After infecting a developer's machine, the malware harvested NPM tokens, GitHub credentials, OpenVSX access tokens, git credential helper data, and the contents of ~/.git-credentials and the GITHUB_TOKEN environment variable. It then validated those stolen tokens against the GitHub API and used any that passed to automatically compromise additional packages and extensions. This worm-like propagation mechanism gave the campaign exponential reach. Koi Security also identified SOCKS proxy deployment and hidden VNC server installation in GlassWorm's payload, effectively turning infected developer machines into criminal infrastructure nodes.

The campaign did not stop after the initial October wave was contained. A second wave hit three VS Code extensions in early November 2025, reaching an additional 10,000 downloads. In late January 2026, the actor compromised a legitimate developer's OpenVSX publishing credentials and silently poisoned four extensions with a combined prior download count of over 22,000. Researchers at Koi Security also identified, from leaked keylogger data found on the attacker's own infrastructure, that the threat actor is assessed to be Russian-speaking and uses an open-source browser extension command-and-control framework called RedExt. A compromised server yielded victim data that included at least one major Middle Eastern government entity.

timeline

October 2025: GlassWorm Wave 1 — 7 OpenVSX extensions, 35,800+ downloads, invisible Unicode payload, Solana C2.
November 2025: Wave 2 — 3 more VS Code extensions (~10,000 downloads). C2 wallet funded November 27.
December 2025–January 2026: Wave 3 — 24+ malicious extensions across both marketplaces; legitimate publisher account compromised.
March 3–9, 2026: GlassWorm GitHub wave — 151+ repositories compromised via invisible Unicode injection (Aikido).
March 8–present, 2026: ForceMemo wave — 240+ Python repositories force-pushed with obfuscated malware (StepSecurity).
March 16, 2026: npm expansion — two React Native packages with 134,000+ monthly downloads compromised.

How ForceMemo Works: The Four-Stage Attack Chain

ForceMemo is built on top of the credential theft GlassWorm already accomplished. The stolen GitHub tokens are the fuel. The attack itself has four distinct stages, and understanding each one is essential for defenders.

Stage 1: Initial Compromise via Malicious IDE Extensions

The entry point is a developer's workstation. GlassWorm spreads through malicious extensions published to the VS Code marketplace and the Cursor IDE extension ecosystem. Cursor, a popular AI-assisted code editor built on the VS Code engine, uses the same extension infrastructure and is equally susceptible. At least one Reddit user independently confirmed this attack vector, reporting that a mysterious user named "null" had committed across most of their repositories and ultimately tracing the infection to a rogue Cursor extension they had installed.

Once GlassWorm's third-stage payload executes on a developer machine, it searches for GitHub tokens across multiple locations: VS Code extension storage, git credential helpers, the ~/.git-credentials file, and the GITHUB_TOKEN environment variable. Validated tokens are exfiltrated to attacker-controlled servers. The developer may have no indication that anything has occurred.

Stage 2: Account Takeover and Repository Selection

With a valid GitHub token in hand, the attacker has write access to every repository the compromised account can push to. StepSecurity's analysis of affected accounts reveals a clear pattern of automated, account-wide compromise. Accounts such as BierOne, wecode-bootcamp-korea, and HydroRoll-Team each had six repositories backdoored using identical methods, confirming that the attacker is running automated tooling rather than manually selecting targets. The campaign targets Python projects specifically: Django web applications, machine learning research code, Streamlit dashboards, Flask APIs, and pip-installable packages.

Stage 3: The Force-Push Injection

This is the stage that makes ForceMemo particularly difficult to detect. Rather than creating a visible new commit or opening a pull request, the attacker uses Git's force-push mechanism to rewrite the repository's default branch history. The process involves rebasing the latest legitimate commit with obfuscated malicious code appended to common Python files, specifically setup.py, main.py, and app.py, and then force-pushing the modified history.

"This technique rewrites git history, preserves the original commit message and author, and leaves no pull request or commit trail in GitHub's UI." — StepSecurity, ForceMemo Campaign Analysis, March 14, 2026

From GitHub's web interface, the repository looks unchanged. The commit message is the same. The author name is the same. The author date is the same. Only the committer date differs, and that is easy to miss during routine inspection. Any developer who clones the repository or runs pip install from it will trigger the malware without any visible warning.

Stage 4: Blockchain C2 and Payload Execution

The appended code is Base64-encoded. When executed, it first checks the system locale. If the locale is set to Russian, execution stops entirely. This is a well-understood operational security pattern associated with Russian-speaking cybercrime groups, designed to avoid infecting systems within the attacker's own country and reduce domestic law enforcement attention.

On all other systems, the malware queries the Solana blockchain. Specifically, it reads transaction memos associated with the wallet address BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC. That wallet was previously attributed to GlassWorm's VS Code extension campaign. The memos contain Base64-encoded URLs pointing to the current payload server. The Solana blockchain records all transactions permanently and publicly, but the attacker controls the private key for the wallet, making the C2 channel effectively unkillable through conventional takedown methods. Between November 27, 2025, and March 13, 2026, StepSecurity documented 50 transactions on this wallet, with the attacker regularly rotating the payload URL, sometimes multiple times in a single day. The blockchain is queried every five seconds on infected systems for updated instructions.

The downloaded payload is an AES-encrypted JavaScript file, with the decryption key delivered via HTTP response headers rather than embedded in the file itself. This prevents static analysis of the payload from yielding actionable content. The decrypted JavaScript is then executed entirely in memory using eval() on macOS and Linux systems, or a Node.js vm.Script sandbox on other platforms. Nothing is written to disk. The payload is assessed to function as a cryptocurrency wallet stealer and credential infostealer based on infrastructure overlap with known campaigns of that type.

warning

The ForceMemo payload is executed entirely in memory and is never written to disk. Standard antivirus scanning of filesystem artifacts will not detect an active infection. Behavioral monitoring of outbound network connections to Solana RPC endpoints is required for detection.

The March 2026 Expansion: npm and React Native

Concurrent with the ForceMemo wave against Python repositories, Aikido Security documented a separate GlassWorm-attributed campaign targeting approximately 151 GitHub repositories between March 3 and March 9 using the older invisible Unicode character technique. The decoded payloads in that campaign retrieved C2 instructions from the same Solana wallet used in ForceMemo, confirming a single threat actor operating multiple simultaneous delivery vectors. Researchers at Aikido noted well-known open-source projects among the compromised repositories, including repos from Wasmer, Reworm, and opencode-bench, raising the potential for significant downstream supply chain impact.

On March 16, 2026, the campaign expanded further into the npm ecosystem. StepSecurity identified malicious releases in two widely used React Native packages: react-native-international-phone-number and react-native-country-select, both published by npm user "astroonauta." Together these packages had an estimated 134,887 monthly downloads at the time of compromise. The malicious versions were pushed within five minutes of each other, at 10:49:29 UTC and 10:54:18 UTC respectively, strongly suggesting coordinated, automated publishing.

The attack in the npm case introduced a new preinstall hook in each package's package.json, pointing to an obfuscated install.js file that was byte-identical across both packages. This file ran automatically the moment a developer executed npm install. It contacted a Solana RPC endpoint to retrieve the payload URL, downloaded the second-stage payload, and executed it. The infrastructure used overlapped with ForceMemo payload servers in the same Vultr IP address block (45.32.150.x). The same Russian locale check was present.

"The technical fingerprint of this campaign is a near-exact match to the ForceMemo campaign we documented on March 14, 2026." — StepSecurity Threat Intelligence, March 16, 2026

Sonatype Security Research independently reviewed the compromised React Native packages and confirmed that the malware attempted to steal npm authentication tokens and GitHub credentials via git credential helpers in addition to delivering the cryptocurrency stealing payload. "Turning a single npm install into a full credential compromise," as Sonatype described it. Both packages have since been removed from the npm registry. Any developer or CI pipeline that installed the compromised versions during the exposure window should be treated as fully compromised.

critical

If any system in your environment installed react-native-country-select@0.3.91 or react-native-international-phone-number@0.11.8 between March 16 and March 17, 2026, treat that machine as compromised. Rotate all npm tokens, GitHub credentials, SSH keys, and any cryptocurrency wallet keys accessible from that system immediately. Check outbound network logs for connections to 45.32.150.251 and 217.69.3.152.

Why the Blockchain C2 Changes the Threat Calculus

Traditional malware campaigns rely on command-and-control servers that can be identified, sinkholed, or taken offline. Law enforcement and security vendors have decades of experience dismantling this infrastructure. GlassWorm sidesteps that entire playbook by using the Solana blockchain as its C2 resolver.

The blockchain records every instruction the attacker posts, permanently and publicly. That is actually useful for researchers: StepSecurity was able to query the C2 wallet address and decode the full history of all 50 transactions, revealing when payload URLs were rotated and identifying at least six rotating payload server IPs, including nodes hosted in Russian network space. However, that same permanence and public accessibility means the attacker's C2 channel cannot be disrupted. There is no domain to seize, no IP to block at the infrastructure level. The blockchain is decentralized by design. As long as the attacker controls the wallet's private key, they control the C2.

The Solana C2 wallet was funded as early as November 27, 2025, more than three months before the first GitHub repository injections in March 2026. StepSecurity notes that the regular payload URL rotation during those intervening months suggests the attacker was running other infection vectors during that period before pivoting to mass GitHub account takeover. The C2 infrastructure was mature and tested before ForceMemo began.

As a backup to the Solana lookup, at least some GlassWorm variants have also been observed using a Google Calendar event as a secondary C2 resolver, parsing event fields to retrieve the payload address. This reflects the same design philosophy: use legitimate, widely trusted infrastructure that cannot be blocked without breaking normal business operations.

Scale of Impact and Attribution

Across all platforms and campaign waves in March 2026 alone, researchers at Aikido, Socket, StepSecurity, and the OpenSourceMalware community collectively identified 433 compromised components attributable to GlassWorm. That figure encompasses GitHub repositories, npm packages, and VS Code and OpenVSX extensions.

Attribution to a single threat actor across all these waves is based on three shared indicators: the same Solana blockchain wallet address used for C2, functionally identical or overlapping payload code, and shared network infrastructure. No single piece of evidence is conclusive, but the convergence across independent analyses from four separate security firms makes the single-actor assessment strong. The Russian locale exclusion, the use of the RedExt C2 framework documented by Koi Security, and keylogger artifacts from the attacker's own machine pointing to a Russian-speaking operator all further tighten the attribution.

The affected Python repositories documented by StepSecurity include amirasaran/django-restful-admin, BierOne/relation-vqa, biodatlab/siriraj-assist, and dozens of repositories under accounts including wecode-bootcamp-korea, HydroRoll-Team, gnlxpy, Fo2sh88, watercrawl, tavasolireza, BishalBudhathoki, iperformance, and KeithSloan. The breadth of affected project types, from machine learning research to web application boilerplate to data crawling tools, confirms that this is not targeted sector-specific espionage. The attacker is casting a wide net, aiming at developer credentials and cryptocurrency assets wherever they can be found.

What Defenders and Developers Need to Do Right Now

The ForceMemo campaign exploits several gaps in standard developer security hygiene. The following actions address the most critical exposure points.

Immediate Actions for Teams Installing Python Packages from GitHub

  1. Search your codebase and CI pipelines for the malware marker variable lzcdrtfxyqiplpd, which StepSecurity identified as a consistent indicator of ForceMemo-injected code across all compromised repositories. A hit on this string in any Python file is a confirmed indicator of compromise.
  2. Verify the committer date on recent commits in any GitHub-sourced Python dependency. Force-pushed commits will show a committer date that is more recent than the author date by a meaningful margin.
  3. Pin Python dependencies to specific commit hashes rather than branch names. Installing from a branch name means you will pull whatever is currently on that branch, including any force-pushed malicious code.
  4. Review all Python files named setup.py, main.py, and app.py in third-party repositories you depend on. Look for unexpected Base64-encoded strings appended to the end of the file.

Credential and Access Token Hygiene

  1. Enable multi-factor authentication on all GitHub accounts. Stolen tokens do not bypass MFA for account login, but they do enable direct API operations. Fine-grained personal access tokens with scoped repository permissions reduce the blast radius of any single token compromise.
  2. Audit installed VS Code and Cursor extensions. Remove any extension whose publisher you cannot independently verify, whose download count appears artificially inflated, or that was installed recently without a clear business justification. GlassWorm has used artificially boosted download counts to appear trustworthy in marketplace listings.
  3. Rotate GitHub tokens, npm tokens, and SSH keys on any machine that has run a GlassWorm-infected extension. If you are unsure whether a machine is infected, treat it as if it is.

CI/CD and Network-Level Monitoring

  1. Implement egress monitoring on GitHub Actions runners. StepSecurity's Harden-Runner is designed specifically for this use case and was the tool that identified anomalous outbound connections in the ForceMemo campaign.
  2. Monitor for outbound connections to Solana RPC endpoints (api.mainnet-beta.solana.com) from developer workstations and CI runners. Legitimate Python development rarely requires direct blockchain queries. Flag and investigate any such connection.
  3. Block or alert on outbound connections to the known ForceMemo payload servers: 45.32.150.97, 45.32.150.251, and 217.69.3.152.

Detection for VS Code and Cursor Extension Compromise

  1. Use the open-source tool anti-trojan-source to scan extension files and repository code for invisible Unicode characters. The tool performs category-based Unicode analysis capable of detecting GlassWorm-style invisible character injection.
  2. Disable automatic extension updates in VS Code where policy allows. GlassWorm's extension-based campaigns delivered malware through auto-updated versions that users received without any action on their part.

Key Takeaways

  1. This is identity-based, not vulnerability-based: ForceMemo does not exploit a GitHub vulnerability. It uses credentials that GlassWorm already stole months ago. Patching GitHub changes nothing. Protecting developer credentials and rotating exposed tokens is the mitigation.
  2. The attack leaves no visible trace in GitHub's UI: Force-pushed commits that preserve the original author and message are indistinguishable from legitimate commits in the GitHub web interface. Out-of-band detection methods are required.
  3. The C2 infrastructure cannot be taken down: The Solana blockchain is the attacker's command channel. Security vendors and law enforcement cannot seize or sinkhole it. This makes infrastructure-level disruption unavailable as a response option.
  4. The campaign is still active and expanding: From VS Code extensions to GitHub repositories to npm packages, GlassWorm's operational tempo has increased, not decreased. New victims are being identified daily. Treat this as an ongoing emergency, not a past event.
  5. Any developer who ran pip install or npm install from a compromised source is at risk: The threshold for infection is as low as a single standard package installation command. CI pipelines, developer workstations, and build agents are all potentially affected.

The GlassWorm actor has demonstrated both persistence and adaptability across five months and multiple distinct campaign waves. The shift from publishing new malicious extensions to compromising legitimate accounts and poisoning trusted repositories represents a maturation in tactics that reduces the attacker's dependence on social engineering developers into installing unknown tools. When a developer's own dependency, a package they have used for years from a maintainer they trust, becomes the delivery vehicle, the human layer of defense stops working. That is precisely the position ForceMemo has engineered. The developer ecosystem's response, whether through better tooling, harder credential security, or mandatory dependency pinning, will determine how much damage this campaign ultimately causes.

— end of briefing