Safeguard
Supply Chain Security•

42 Malicious RubyGems Hid Reverse Shells in extconf.rb

On 5 October 2026 one RubyGems account published 42 crypto-themed gems in about an hour. A fake native extension opened a reverse shell at install time, but only on real developer machines.

Safeguard Security Team
5 min read

On 5 October 2026, the RubyGems account reqthrottle_3474 published 42 malicious gems in about one hour, according to SafeDep's analysis. Most are named like cryptocurrency developer tools, and the last 16 are typosquats of real gems such as bitcion and kecack. Each declared a fake native extension so that its extconf.rb ran during gem install and either opened a reverse shell or fetched a second stage. All 42 are now gone from RubyGems, and each has an OSV malware record.

What's affected

All 42 gems were published at version 1.0.0 or 1.0.1. SafeDep groups them into two templates:

  • Reverse shell, 11 gems. Connects to 45.138.12.177 on port 8089 or 8090 and hands over /bin/sh with the installing user's permissions, reconnecting every 30 seconds. SafeDep names req-throttle-mini, bitcoin-rpc-lite, wallet-crypto-utils and web3-eth-utils among them.
  • Second stage, 31 gems. After a 20 to 40 minute wait, downloads wgkit.tar.gz from port 8092 on the same host into /tmp/.w1.tgz, extracts it to /tmp/.w1/, runs wg_install.sh and deletes the files.

The names fall into three groups:

  • Rate limiting decoys: req-throttle-mini, throttle-requests, rate-limit-mini, request-guard.
  • Crypto utilities: bitcoin-rpc-lite, web3-eth-utils, wallet-crypto-utils, eth-keystore-utils, btc-wallet-tools, eth-address-utils, crypto-mnemonic-tools, wallet-backup-tool, bip39-wordlist-utils, hdkey-derive-helper, blockchain-sync-utils, tx-broadcast-utils, electrum-protocol-lite, coinmarket-utils, web3-sign-helper, crypto-key-utils, bitcoin-address-utils, ethereum-tx-helper, merkle-proof-lite, utxo-set-utils, lightning-invoice-utils, base58-check-helper.
  • Typosquats: bitcion-ruby, bitcoij-ruby, bitcion, bitciin, etheremu.rb, etherdum.rb, tron-rb, lightinng-invoice, ligbtning-invoice, lighthing-invoice, crypti-toolbox, crylto-toolbox, cryoto-toolbox, kecack, keccka, solaan-ruby.

The evasion is what makes this campaign worth studying. Before doing anything, extconf.rb exits if it sees CI variables such as CI, GITHUB_ACTIONS or GITLAB_CI, a sandbox-like hostname or username, a working directory under /tmp/ or /workspace/, or uptime under 30 minutes. It only proceeds if the home directory holds something like .ssh, .gitconfig, .npmrc, .gem/credentials or .bundle. As SafeDep puts it, a scanner or CI job sees a normal install with no network traffic.

How to check if you're exposed

Check lock files and installed gems on developer machines:

GEMS='req-throttle-mini|throttle-requests|rate-limit-mini|request-guard|bitcoin-rpc-lite|web3-eth-utils|wallet-crypto-utils|eth-keystore-utils|btc-wallet-tools|eth-address-utils|crypto-mnemonic-tools|wallet-backup-tool|bip39-wordlist-utils|hdkey-derive-helper|blockchain-sync-utils|tx-broadcast-utils|electrum-protocol-lite|coinmarket-utils|web3-sign-helper|crypto-key-utils|bitcoin-address-utils|ethereum-tx-helper|merkle-proof-lite|utxo-set-utils|lightning-invoice-utils|base58-check-helper|bitcion-ruby|bitcoij-ruby|bitcion|bitciin|etheremu\.rb|etherdum\.rb|tron-rb|lightinng-invoice|ligbtning-invoice|lighthing-invoice|crypti-toolbox|crylto-toolbox|cryoto-toolbox|kecack|keccka|solaan-ruby'
gem list | grep -E "^($GEMS) "
grep -rnE "^    ($GEMS) \(" --include=Gemfile.lock .

Then look for the runtime artifacts and connections:

ls -la /tmp/.w1.tgz /tmp/.w1/ 2>/dev/null
lsof -nP -i @45.138.12.177 2>/dev/null
ps -eo pid,ppid,etime,command | awk '$2 == 1 && /ruby/'

The loader forks twice and detaches with setsid, so a payload that is still running shows up as a ruby process whose parent is PID 1. In network logs, search for any connection to 45.138.12.177 on ports 8089, 8090 or 8092.

What to do now

  1. If a workstation installed one of these gems, treat it and its credentials as compromised. SafeDep's guidance is explicit for the reverse-shell gems, and the second stage runs an unknown script.
  2. Rotate from a clean machine. SSH keys, ~/.gem/credentials, npm tokens, Git credentials, cloud keys and any wallet keys or seed phrases on the host.
  3. Block 45.138.12.177 at the egress firewall and alert on any historical hits.
  4. Make native extensions visible in review. A gem that declares extensions runs extconf.rb on install. New dependencies with native extensions deserve a look, especially small utility gems that have no reason to compile anything.
  5. Install new gems in a disposable environment first. Keep in mind that this campaign deliberately stays quiet in short-lived sandboxes, so pair it with checks against malware feeds before code reaches a laptop.

Why it matters

This campaign was built to pass automated review. A sandbox with fresh uptime, no SSH keys and a CI variable set would see a gem that installs cleanly and does nothing. Dynamic analysis still has value, but this is a clear signal that attackers test against it and aim at the machine that holds the keys: the developer's laptop.

It also shows why "it's only a dev dependency" is not comforting. The payload ran at install time, with the developer's permissions, before any code was required from an application. The protective step is upstream of the install: knowing that a package is new, single-author, has a native extension it doesn't need, and matches a known-malicious record.

Try it yourself

Run this in a Ruby project to list every installed gem that declares a native extension:

ruby -e 'Gem::Specification.each { |s| puts "#{s.name} #{s.version}" unless s.extensions.empty? }' | sort -u

Ask, for each one, whether you expected compiled code there. Then check the rest of your Gemfile.lock against known malicious packages.

Click through it at your own pace, or open it full screen.

Quick check

Why would a CI scan of these gems show nothing suspicious?

extconf.rb exits early when it sees CI variables, sandbox-like hostnames or usernames, temporary working directories or low uptime, so the install looks normal with no network traffic.

How did the gems run code during gem install?

Each gemspec declared a native extension pointing to an extconf.rb file, which RubyGems executes as part of installation.

Are the gems still downloadable?

No. All 42 return "not found" from the RubyGems API as of 18 October 2026, and each has an OSV malware record.

Sources

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.