GlassWorm Expands from VS Code to Python: ForceMemo Campaign Confirmed
The GlassWorm campaign — the self-propagating supply-chain worm first identified targeting VS Code extensions — has launched a new attack vector. Researchers at StepSecurity have confirmed a sub-campaign dubbed ForceMemo, active since March 8, 2026, in which the threat actor uses previously harvested GitHub developer tokens to perform silent force-push operations on hundreds of Python repositories.
The technique is unprecedented in documented supply-chain attacks: by rewriting Git history rather than opening pull requests, the injections leave no trace in GitHub's standard activity timeline, making them invisible to routine security reviews.
Campaign Overview
| Attribute | Value |
|---|---|
| Campaign name | ForceMemo (GlassWorm sub-campaign) |
| First observed | March 8, 2026 |
| Status | Active and ongoing (as of March 16, 2026) |
| Attack method | Force-push via stolen GitHub tokens to rewrite history |
| Repos affected | "Hundreds" of Python repositories (StepSecurity) |
| Broader GlassWorm | 151+ GitHub repos, 72+ Open VSX extensions |
| Attribution | Russian-speaking threat actor (locale-skip gating) |
| C2 method | Solana blockchain dead-drop + Google Calendar fallback |
How ForceMemo Works
Phase 1 — Token Harvesting
Tokens used in ForceMemo were harvested from developers previously infected by GlassWorm's Wave 1–4 VS Code extension campaigns, which silently exfiltrated GitHub OAuth tokens and personal access tokens from developer workstations. Those credentials are now being weaponized in a second wave.
Phase 2 — Silent Force-Push Injection
Using stolen tokens, the attacker performs a git push --force directly to the default branch of the target repository:
- The force-push rewrites the most recent commit in place — preserving the original commit message, author name, and author date
- The result is indistinguishable from a legitimate commit in GitHub's UI
- No pull request is created, no new commit appears in the activity feed, and no contributor notification is triggered
- StepSecurity describes this as the first documented supply-chain campaign to use this injection method
Phase 3 — Payload Execution
The injected Base64-encoded payload is appended to entry-point files — setup.py, main.py, or app.py. On execution it performs:
- Locale check: If the system locale is Russian (
ru), execution aborts entirely - Solana C2 lookup: Connects to
api.mainnet-beta.solana.comand queries transaction memos on the hardcoded wallet addressBjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SCfor a Base64-encoded payload URL - Google Calendar fallback: If the Solana RPC call fails, the malware queries a specific Calendar event and extracts the payload URL from the event title
- Second-stage payload delivery: The resolved URL delivers the full GlassWorm post-exploitation module
Targeted Project Types
The campaign specifically targets Python projects with broad install or download footprints:
- Django web applications
- Machine learning research codebases
- Streamlit dashboard apps
- PyPI packages — both published and in-development
Aikido Security assessed the campaign likely uses LLM-generated cover commits to make injections appear contextually appropriate across diverse codebases.
Why This Technique Is Dangerous
| Property | Impact |
|---|---|
| No visible commit | Does not appear in GitHub activity timeline |
| Preserved commit metadata | Author, date, and message match original — indistinguishable from legitimate code |
| No PR / review process | Bypasses code review workflows entirely |
| Blockchain C2 | Payload URL cannot be taken down via domain seizure |
| Solana wallet link | Same wallet used in VS Code GlassWorm campaign — definitively same actor |
| Locale gating | Russian-locale systems skipped — protects actor's own environment |
Indicators of Compromise
| IOC Type | Value |
|---|---|
| Solana wallet (C2) | BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC |
| Solana RPC endpoint | api.mainnet-beta.solana.com |
| Injection targets | setup.py, main.py, app.py — Base64 blob appended at end of file |
| Known C2 IPs (VS Code waves) | 217.69.3[.]218, 199.247.10[.]166 |
Impact Assessment
| Impact Area | Description |
|---|---|
| Developer trust | Force-pushed commits bypass review; infected code ships as "approved" |
| PyPI ecosystem | Published packages may contain injected payload reaching all downstream users |
| CI/CD pipelines | Build systems that pull from GitHub may execute the malicious payload during builds |
| Credential exposure | Any developer cloning or contributing to a poisoned repo risks secondary infection |
| Attribution link | Same Solana wallet as VSCode campaign confirms unified actor — GlassWorm is actively evolving |
Recommendations
For Developers
- Audit recent commits on your repos for force-pushes — check
git reflogfor HEAD rewrites that weren't initiated by your team - Rotate all GitHub tokens immediately if you previously installed any extensions identified as GlassWorm-infected (see prior advisories)
- Scan Python entry-point files (
setup.py,main.py,app.py) for Base64 blobs appended at the end of the file - Enable branch protection rules — require pull request reviews and disable force pushes on default branches
For Security Teams
- Monitor for Solana RPC calls from build or runtime environments — legitimate Python applications have no reason to connect to
api.mainnet-beta.solana.com - Audit GitHub organization token permissions and revoke any tokens not explicitly provisioned by your team
- Add
git push --forcedetection to your GitHub audit log monitoring — force-pushes to default branches should trigger alerts - Check CI/CD pipelines for unexpected network connections during build steps
For PyPI Maintainers
- Review recent releases for any unexpected changes to
setup.pyor entry-point files - Yank compromised versions immediately if injection is confirmed
- Publish integrity checksums to help downstream users verify package authenticity
Key Takeaways
- GlassWorm has evolved from VS Code to Python repos — the campaign continues expanding its attack surface with new delivery methods
- ForceMemo's force-push technique is undocumented in prior supply chain attacks — standard security reviews and diff-watching tools won't catch it
- The Solana C2 mechanism makes payload URLs untakeable-down — even after discovery, the C2 infrastructure remains operational
- The same Russian-attribution indicators appear in ForceMemo — locale gating and Solana wallet links definitively connect both campaigns
- Hundreds of Python repos are already compromised — any project that imported from an affected dependency should be treated as potentially tainted
- Enable branch protection and force-push alerts — these simple controls would have blocked the attack vector entirely
Sources
- The Hacker News — GlassWorm Attack Uses Stolen GitHub Tokens to Force-Push Malware Into Python Repos
- StepSecurity — ForceMemo: Hundreds of GitHub Python Repos Compromised via Account Takeover and Force-Push
- Aikido Security — Glassworm Returns: Invisible Unicode Malware Found in 150+ GitHub Repositories
- SecurityWeek — ForceMemo: Python Repositories Compromised in GlassWorm Aftermath