Skip to main content
433 Python Packages Weaponized Through GitHub Force-PushIncident
3 min readFor Security Engineers

433 Python Packages Weaponized Through GitHub Force-Push

Incident Overview

On March 8, 2026, attackers exploited stolen GitHub personal access tokens to force-push malicious code into legitimate Python repositories. This campaign, known as GlassWorm/ForceMemo, affected over 433 projects by injecting obfuscated malware, turning each package into a distribution node. The attack bypassed standard pull request workflows, allowing direct writes to main branches using valid credentials.

The malware used geofencing to avoid detection and utilized GitHub's infrastructure as its command-and-control layer. Developers who pulled these packages unknowingly installed backdoors, risking data exfiltration and network spread.

Attack Timeline

March 8, 2026: First confirmed force-push of malicious code to a Python repository using a stolen token.

March-April 2026: The campaign expanded to over 433 packages. StepSecurity researchers identified a pattern of force-pushes to dormant or infrequently maintained repositories.

Detection: StepSecurity traced the attack through GitHub's audit logs, identifying the use of stolen tokens and force-push patterns that bypassed branch protection rules.

Current status: The campaign is still active. Many repositories remain compromised, and systems that installed these packages are at risk.

Failed or Missing Controls

Token Management: Stolen GitHub tokens had unrestricted write access and lacked expiration or scope restrictions. These tokens were treated as long-lived credentials.

Branch Protection: Repositories lacked branch protection rules or allowed force-pushes by authenticated users, assuming token possession equated to authorization.

Commit Signing: Affected repositories did not enforce GPG or SSH commit signature verification, making malware commits appear legitimate.

Supply Chain Verification: Consumers installed packages without verifying commit signatures or monitoring for unexpected changes. The Python Package Index (PyPI) mirrored these compromised repositories without additional checks.

Audit Log Monitoring: Organizations did not alert on force-push events, especially those rewriting commit history. The attack pattern was visible in GitHub's audit logs but went unnoticed.

Dependency Pinning: Projects using pip install package-name without version pinning automatically pulled compromised code, lacking hash verification or lockfile validation.

Relevant Standards

NIST 800-53 Rev 5 Requirement IA-5(2) mandates that authenticators have a limited lifetime and are refreshed before expiration. Long-lived GitHub tokens with write access violate this control.

ISO 27001 Annex A Controls 8.23 and 8.24 require code integrity verification before deployment. Installing packages without signature verification fails these controls.

NIST CSF v2.0 function PR.DS-6 states that integrity checking mechanisms must verify software integrity. Force-pushing code without signature requirements lacks this verification.

PCI DSS v4.0.1 Requirement 6.3.2 requires maintaining the security of custom software through code review and change management. Force-pushes bypassing pull requests violate this requirement.

SOC 2 Type II Common Criteria CC6.1 requires logical access controls for authorized users. A stolen token is unauthorized, but without expiration policies and force-push restrictions, the system cannot distinguish legitimate from compromised access.

Action Items for Your Team

Rotate and Scope Tokens: Audit all GitHub personal access tokens and deploy keys. Set maximum lifetimes (30 days for personal tokens, 90 days for service accounts). Use fine-grained tokens with limited access. Revoke unnecessary force-push capabilities.

Enforce Branch Protection: Configure rules that prohibit force-pushes, even from administrators. Require signed commits for production branches to ensure security.

Implement Commit Signing: Require GPG or SSH signature verification on all commits to protected branches. Distribute developers' public keys through verified channels and configure GitHub to reject unsigned commits.

Monitor Audit Logs: Alert on force-push events, especially those rewriting multiple commits. Monitor token usage from unexpected IP ranges or geographic locations. Analyze audit patterns for visibility.

Pin Dependencies with Hash Verification: Use lockfiles specifying exact versions and SHA256 hashes. Use tools like pip-audit or safety to scan for compromised packages. Verify hashes during deployment.

Repository Integrity Monitoring: Run regular checks comparing current repository states against known-good snapshots. Alert on unexpected commit history changes or new contributors without access requests.

Segment Token Permissions: Create separate tokens for CI/CD systems, developer workstations, and automated tools. Use GitHub Actions' OIDC tokens instead of long-lived secrets.

Test Incident Response: Simulate scenarios where unauthorized code is detected. Ensure you can identify compromised tokens, assess the impact, and respond within 15 minutes.

The attackers exploited GitHub tokens as a new perimeter, understanding that repository access is often treated as binary. Your response should match this sophistication. Start with token rotation, branch protection, and audit monitoring to build a robust defense.

Topics:Incident

You Might Also Like