If you thought the GlassWorm campaign was bad, its sequel is worse. ForceMemo — first reported by StepSecurity on March 18, 2026 — is an active supply-chain attack that has silently backdoored hundreds of Python repositories across GitHub. The malware uses Git's force-push to rewrite history, making injections invisible to anyone who doesn't know exactly where to look, and leverages the Solana blockchain as an uncensorable command-and-control channel.
This isn't theoretical. It's happening right now, with new repos being compromised daily.
From Credential Theft to Mass Compromise
ForceMemo is the direct downstream consequence of GlassWorm, the earlier campaign that spread through malicious VS Code and Cursor extensions. GlassWorm's Stage 3 payload includes a dedicated credential harvesting module that steals GitHub tokens from:
-
git credential fill(system credential manager) - VS Code extension storage databases
-
~/.git-credentials(plaintext credential file) - The
GITHUB_TOKENenvironment variable
Once ForceMemo operators have these tokens, they don't just compromise one repository per victim — they hit every repo on the account. User BierOne had 6 repositories compromised. The organization wecode-bootcamp-korea lost 6. HydroRoll-Team lost 6. The pattern is clear: one credential leak, total developer account wipeout.
Targeted project types: Django apps, Flask APIs, ML research code, Streamlit dashboards, and pip-installable packages. If it's Python and it's on GitHub, it's a target.
The Stealth Technique: Force-Push History Rewriting
This is what makes ForceMemo genuinely terrifying. Instead of creating pull requests or adding new commits (which would appear in activity feeds and notification emails), the attacker:
- Takes the latest legitimate commit on the repo's default branch
-
Rebases it, appending obfuscated malware to a key Python file (
setup.py,main.py,app.py) - Force-pushes the modified commit back to the default branch
The result: the commit message, author name, and author date are identical to the original. There's no new commit in the log. No pull request. No notification. The GitHub UI looks completely unchanged.
The Only Fingerprints
Two subtle indicators betray the attack:
1. Committer date vs. author date mismatch
# Legitimate author date preserved:
Author Date: 2017-04-24
# But the committer date reveals the actual injection:
Committer Date: 2026-03-10
# That's a 9-year gap on amirasaran/request_validator
StepSecurity found gaps ranging from 33 days to 9 years across compromised repositories.
2. The "null" committer email
Across hundreds of malicious commits, the committer email is consistently set to the string "null" — a fingerprint of the attacker's tooling. This is your most reliable detection signal.
GitHub Events API Evidence
The force-push is visible in the Events API, which preserves the before and after commit SHAs:
{
"type": "PushEvent",
"actor": "amirasaran",
"created_at": "2026-03-10T21:58:02Z",
"ref": "refs/heads/master",
"before": "260ca635...", // clean commit (legitimate PR merge)
"after": "17849e1b..." // malicious rebased commit
}
Anyone running pip install from the after commit gets owned.
The Payload: Three-Layer Obfuscation + Solana C2
Obfuscation Layers
The injected code is appended to the end of legitimate Python files. It uses three layers:
# Layer 1: Base64 decode
# Layer 2: Zlib decompress
# Layer 3: XOR decrypt (key: 134)
# Marker variable (identical across ALL compromised repos):
lzcdrtfxyqiplpd = '<4,800-character base64 blob>'
The variable name lzcdrtfxyqiplpd is the universal indicator. Search for it:
GitHub Code Search: lzcdrtfxyqiplpd
CIS Exclusion Check
Before executing, the malware checks locale, timezone, and UTC offset. If the system is Russian, it exits. This is a well-documented pattern in Eastern European cybercrime — don't attack domestic systems.
The deobfuscated source contains Russian comments:
# "Эмуляция объекта Buffer из Node.js"
# (Emulation of Node.js Buffer object)
# "Получение подписей для адреса Solana"
# (Getting signatures for Solana address)
Solana Blockchain as C2
Instead of a traditional C2 domain (which can be seized or sinkholed), ForceMemo reads instructions from Solana transaction memos:
C2 Wallet: BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC
Active since: November 27, 2025
The malware queries this wallet via 9 fallback RPC endpoints:
| Endpoint | Purpose |
|---|---|
api.mainnet-beta.solana.com |
Primary Solana RPC |
solana-mainnet.gateway.tatum.io |
Tatum gateway |
go.getblock.us |
GetBlock |
solana-rpc.publicnode.com |
Public node |
api.blockeden.xyz |
BlockEden |
solana.drpc.org |
dRPC |
solana.leorpc.com |
Leo RPC |
solana.api.onfinality.io |
OnFinality |
solana.api.pocket.network |
Pocket Network |
Why this matters: The attacker can update the payload URL at any time by posting a new Solana transaction. The instructions are immutable and censorship-resistant. You can't take down a blockchain memo.
The Final Stage
Once the C2 memo is read, the malware:
- Downloads Node.js v22.9.0 from nodejs.org (cross-platform: Windows/macOS/Linux, x64/ARM)
- Fetches an AES-encrypted JavaScript payload from the URL in the memo
- Decrypts and executes using the downloaded Node.js runtime
-
Creates
~/init.jsonwith a 2-day timer to prevent repeated execution
The final payload harvests SSH keys, GitHub tokens, cryptocurrency wallet data, and installs remote access tooling.
Why DeFi Developers Should Care
This isn't just a "Python security" story. The overlap with the crypto ecosystem is direct:
1. Your dev environment IS your wallet. If you develop DeFi protocols, your machine likely has private keys, deployment scripts, .env files with RPC credentials, and wallet seed phrases. ForceMemo's final payload targets all of these.
2. Solana validator operators at risk. Anyone running Solana infrastructure who installs Python tooling from GitHub is a potential victim. Validator keys have direct financial value.
3. Smart contract audit firms. Auditors frequently clone and build client repositories. A compromised setup.py in a client's dependency could backdoor the auditor's machine.
4. CI/CD pipelines. GitHub Actions workflows that run pip install from Git repos (rather than PyPI) execute setup.py automatically. The malware runs in your CI environment with access to whatever secrets are available.
Detection Checklist
For Individual Developers
- [ ] Search your cloned repos for the marker:
grep -r "lzcdrtfxyqiplpd" ~/ - [ ] Check for
~/init.json— its presence means the payload already ran - [ ] Look for
~/node-v22.9.0-*folders — the malware's Node.js runtime - [ ] Review your Git credential storage:
cat ~/.git-credentials - [ ] Check VS Code extensions for anything unfamiliar installed recently
- [ ] Rotate GitHub tokens immediately if you used any Cursor/VS Code extension from an untrusted source
For Repository Maintainers
# Check for committer date vs author date mismatches:
git log --format='%H | Author: %ai | Committer: %ci | Email: %ce' -5
# Look for "null" committer email:
git log --format='%ce' | grep -i "null"
# Compare current HEAD with last known good commit:
git diff <known-good-sha> HEAD
For CI/CD Pipelines
- Pin dependencies to specific commit SHAs, not branches
- Use
pip installfrom PyPI (not raw GitHub repos) wherever possible - Enable StepSecurity Harden-Runner or equivalent network monitoring
- Monitor for unexpected outbound connections to Solana RPC endpoints
Mitigation: Git Configuration Hardening
Prevent force-push attacks on your repos:
# Require signed commits on protected branches
# (GitHub Settings → Branches → Branch protection rules)
# Enable branch protection:
# ✅ Require pull request reviews before merging
# ✅ Require signed commits
# ✅ Do not allow force pushes
# ✅ Do not allow deletions
# For organizations, enforce at the org level:
# Settings → Code security → Push protection
Credential hygiene:
# Use SSH keys instead of stored tokens
# If you must use tokens, scope them minimally:
# - repo:status (read-only)
# - NOT repo (full access)
# Never store tokens in plaintext:
# Bad: ~/.git-credentials
# Good: git credential-store with OS keychain
# Rotate tokens regularly:
gh auth refresh
Timeline
| Date | Event |
|---|---|
| Nov 27, 2025 | Solana C2 wallet first active |
| Jan–Mar 2026 | GlassWorm campaign steals developer credentials |
| Mar 8, 2026 | Earliest confirmed ForceMemo injection |
| Mar 10, 2026 | django-restful-admin force-push detected |
| Mar 13, 2026 | Multiple ML research repos compromised |
| Mar 18, 2026 | StepSecurity publishes initial report |
| Mar 20, 2026 | Campaign still active, new repos being hit |
The Bigger Picture: Blockchain Infrastructure as Attack Surface
ForceMemo, GlassWorm, and Windsurf IDE attacks all share a common thread: Solana's permissionless transaction memo system is being systematically weaponized as C2 infrastructure. The same property that makes blockchain censorship-resistant makes it an ideal dead drop for malware operators.
This creates an uncomfortable tension for the Solana ecosystem. The protocol works exactly as designed — anyone can post a memo to the blockchain, and it persists forever. But "working as designed" doesn't mean "working as intended" when the design enables uncensorable malware infrastructure.
The DeFi security community needs to reckon with this. Blocking specific RPC endpoints is a game of whack-a-mole (the malware already uses 9 fallbacks). The real solutions lie in:
- Developer environment isolation — Don't develop DeFi on the same machine where you store keys
- Supply chain verification — Pin, hash, verify everything you install
- Credential compartmentalization — No single token should give access to everything
- Runtime monitoring — Catch the payload phone-home even if you miss the injection
The supply chain is only as strong as its weakest credential. In 2026, that credential is probably sitting in a VS Code extension database on a developer's laptop.
This article is part of the DeFi Security Research series. Follow for weekly deep dives into smart contract vulnerabilities, audit methodologies, and DeFi security tooling.
References:
Top comments (0)