ghtier
← Back to User plane incidents
UserOctober 2025 – March 2026

GlassWorm: editor extensions that steal GitHub tokens and force-push

GlassWorm started on 17 October 2025 as malicious VS Code extensions on Open VSX and the VS Code Marketplace. The loader is written in invisible Unicode characters, so it shows as blank space in editors, terminals and GitHub's diff view. Once installed, it takes GitHub, Git, npm and Open VSX credentials from the developer's machine, uses them to infect more extensions, and turns the machine into a proxy with remote access. From late 2025 the stolen GitHub tokens were also used against repositories. In March 2026 the same actor took the latest real commit in hundreds of Python repositories, added an obfuscated payload to files such as setup.py, and force-pushed it to the default branch. The author and commit message were kept, so only the committer date gives it away. Aikido found at least 151 affected repositories through code search in 3 to 9 March, and StepSecurity found hundreds more across hundreds of accounts, which it tracks as ForceMemo and ties to GlassWorm through the same command wallet. A force-push like this only works where the branch allows it.

Permissions abused

Tokens stored on the developer's machinecontents:write (force-push to the default branch)

On the permission reference

Reported by: Aikido, StepSecurity

How it unfolded

  1. 1

    A malicious extension is installed

    Extensions on Open VSX and the VS Code Marketplace carried a loader hidden in invisible Unicode characters. Reviewing the source shows nothing.

  2. 2

    Credentials are taken from the machine

    The payload reads GitHub tokens from git credential fill, VS Code's extension storage, ~/.git-credentials and environment variables, along with npm and Open VSX tokens.

  3. 3

    The worm publishes itself

    Stolen registry tokens are used to push infected versions of other extensions the victim maintains.

  4. 4

    Repositories are rewritten with a force-push

    The attacker rebases the latest commit with the payload added and force-pushes it to the default branch. The original author and message stay, so the history looks unchanged at a glance.

Mitigations

  • Block force pushes on default branches with a ruleset — the GitHub side of the campaign was nothing but force-pushes

  • Require signed commits — a rewritten commit loses the original signature

  • Allow-list IDE extensions centrally — the way in was an extension the developer chose to install

  • Keep long-lived tokens off developer laptops and set a maximum token lifetime — every token on the machine was taken

  • Alert on force pushes in the audit log — the committer date is the only visible trace

Frameworks

Part of

Ongoing. First seen October 2025, last seen 13 March 2026. At least 151 GitHub repositories found by code search in 3 to 9 March 2026; StepSecurity found hundreds more (as of 13 March 2026, source). Mapping by ghtier, not yet reviewed. Threat landscape