astropod sign in

SleeperGem: Dormant RubyGems Accounts Reactivated to Deliver a Persistent Backdoor

Published on gastropod.io - 07-19-2026

SleeperGem: Dormant RubyGems Accounts Reactivated to Deliver a Persistent Backdoor


Tags: rubygems, supply-chain-attack, credential-theft, provenance, dormant-maintainer, ruby, vulnerability-intelligence, software-supply-chain-security


For more than a year, RubyGems has watched from the sidelines while npm and PyPI absorbed one supply chain compromise after another. That streak ended this weekend.

Over July 18 and 19, an attacker pushed malicious versions of three gems to RubyGems.org in a coordinated campaign that Aikido Security spotted in its triage queue and named SleeperGem. The name fits the trick at the center of it. These were not freshly minted throwaway packages that nobody would recognize. Two of the compromised accounts had been dormant for years, one gem last shipping in 2020 and another with roots going back to 2017, and they came back to life within hours of each other to push the same malicious dependency into libraries people already trusted.

The three packages: git_credential_manager, a brand-new gem impersonating Microsoft's official Git Credential Manager; Dendreo, which sat quiet for nearly six years before suddenly publishing two new versions on the same afternoon; and fastlane-plugin-run_tests_firebase_testlab, a completely unrelated project with over 574,000 total downloads that belonged to a different maintainer entirely. That last detail is the worrying one. It suggests the compromise reached past a single hijacked account.

What the malware actually does

Each malicious release is a loader, and a fairly patient one. You can watch the attacker build it out across four versions of git_credential_manager over about nine hours in two sittings. Version 2.8.0 was already a working dropper, fetching binaries from a public Forgejo instance at git.disroot.org with certificate verification explicitly turned off. Version 2.8.1, twenty-four minutes later, changed one thing: it piped the output to /dev/null to be quieter. Then an eight-hour gap, presumably for sleep, before version 2.8.2 wired the installer directly into the gem's load path so that merely require-ing the library kicks everything off, with the line that fires the payload left commented out. Seventeen minutes after that, version 2.8.3 uncommented it. One character between staged and live.

Two things make this nastier than the usual install-time trojan. First, the code runs on require, not just on install, so pinning a lockfile and skipping postinstall scripts does not save you. Second, it deliberately checks for around thirty CI environment variables and does nothing if it finds one. This malware does not want your ephemeral build runners. It wants developer laptops, where the SSH keys and cloud credentials and browser secrets actually live. On a machine it likes, it drops a native daemon, installs persistence twice over as both a systemd user service and a cron entry, and probes for a path to root.

StepSecurity ran every version through their runtime tooling and captured the full kill chain, which is worth reading if you want the process-tree-level detail. The short version: if any of these gems touched a developer machine in your org, treat that machine and every secret reachable from it as compromised, pull the daemon from ~/.local/share/gcm/, and rotate.

The affected versions to grep your lockfiles for: git_credential_manager 2.8.0 through 2.8.3, Dendreo 1.1.3 and 1.1.4, and fastlane-plugin-run_tests_firebase_testlab 0.3.2.

Some source reading

The thread that runs through all of it

Strip away the daemon and the Forgejo host and the setuid trickery, and the tell was there before any of the payload ran. Every one of these malicious releases showed up on RubyGems with no corresponding tag in the source project. The gem said it came from a real, trusted library, but nothing in its provenance backed that up. Layer on the behavioral signal, packages that had shipped nothing in six or seven years suddenly publishing versions minutes apart, and you have two independent reasons to stop the artifact at the door rather than after it has already been require-d into a build.

That gap between "declares itself as X" and "actually verifiable as X" is the thing we built Gastropod around. When a gem flows through, its identity gets pinned to a real digest and its provenance checked against what the source actually attests, so a version that appears on the registry with no matching upstream tag is a mismatch you see at intake, not a forensics exercise you run afterward. And because every pull is attributed to a principal in the audit spine, the question "did anyone here actually pull 2.8.3, and onto whose machine" has an answer sitting in one query instead of a fleet-wide scramble.

We are not going to pretend a registry proxy would have caught the daemon's every trick; the credential theft lives in a native binary that runs well downstream of where we sit. But the whole point of SleeperGem was that it looked harmless enough to slip past a human glance, and provenance does not glance. If your team ships Ruby and this weekend had you grepping Gemfile.lock by hand, that is a decent afternoon to see what your own artifacts look like through it.

Because the uncomfortable takeaway from SleeperGem is that a maintainer account going quiet for six years does not look like a risk to anyone. Which is exactly why it was worth stealing.

← news