# ForceMemo: Hundreds of GitHub Python Repos Compromised via Account Takeover and Force-Push

GlassWorm infostealer harvested GitHub tokens from VS Code/Cursor extensions, letting attacker force-push Solana-C2 malware into hundreds of Python repos.

- Payout: Real-world hack
- Severity: critical
- Program: GitHub
- Analysis by: StepSecurity
- Disclosed: 2026-03-26
- Write-up quality: 8/10
- Original: https://www.stepsecurity.io/blog/forcememo-hundreds-of-github-python-repos-compromised-via-account-takeover-and-force-push
- Library page: https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-forcememo-hundreds-of-github-python-repos-compromised-via-account-takeover-and-force-push
- Tags: area:oss domain:oss impact:data-leak impact:mass-exploit kind:incident platform:threat-intel sev:critical tech:github-actions tech:solana technique:chained technique:recon technique:source-review vuln:secrets-leak

**Target:** GitHub repositories / Python setup.py, main.py, app.py entry points
**Root cause:** Developer machines infected by GlassWorm via malicious VS Code/Cursor extensions; stage-3 payload harvested GitHub tokens from git credential fill, extension storage, ~/.git-credentials and GITHUB_TOKEN. Stolen tokens let attacker rebase-and-force-push malware onto default branches, preserving author/message so only committer date reveals tampering.
**Steps:**
1. Compromise dev via malicious VS Code/Cursor extension (GlassWorm) that runs credential-theft module
2. Harvest tokens: `git credential fill`, VS Code extension storage, `~/.git-credentials`, `$GITHUB_TOKEN`; validate against GitHub API
3. Clone victim repo, take latest default-branch commit, append obfuscated blob to setup.py/main.py/app.py
4. Rebase preserving author/message/date, set committer email to `null`, force-push to default branch
5. Malware: base64-decode `lzcdrtfxyqiplpd`, zlib-decompress, XOR with key 134, `exec(compile(...))`
6. Skip if Russian locale/timezone; query Solana address `BjVeAjPrSKFiingBn4vZvghsGj9KCE8AJVtbc9S8o8SC` memos across 9 RPC fallbacks for payload URL
7. Download Node.js v22.9.0, fetch AES-encrypted JS (IV/key in HTTP headers), write `i.js`, execute; persist via `~/init.json` 2-day timer
**How found:** Reddit user noticed commits authored by "null" across most of their repos and traced infection to a compromised Cursor extension; StepSecurity pivoted via the shared marker variable `lzcdrtfxyqiplpd` in GitHub code search, correlated committer-vs-author date gaps, GitHub Events API PushEvent before/after SHAs, and on-chain Solana memo decoding.
**Exploitation:** Victim runs `pip install .` or `python setup.py install` from a compromised repo; appended code executes, contacts Solana memo C2, downloads Node.js and AES-encrypted JS payload, runs it to steal browser crypto wallet seeds, cookies, credentials and SSH keys; 2-day recheck timer maintains access.
**Escalation:** Account-level takeover: every repo under a compromised account gets injected (e.g. BierOne 6 repos, wecode-bootcamp-korea 6). Blockchain C2 with 9 RPC fallbacks and rotating payload IPs makes takedown/censorship hard; DHT fallback on port 10000.
**Insight:** Detect supply-chain tampering by diffing committer date vs author date on default-branch commits and by grepping for a shared marker variable across GitHub code search; on-chain memo C2s are enumerable via the wallet's full transaction history, revealing payload-server rotation and infrastructure.
