Keypoints
- Phylum detected multiple malicious npm packages that impersonated the popular ethers library and its forks.
- The packages were designed to exfiltrate Ethereum private keys by sending them to a remote endpoint at ether-sign[.]com.
- The attacker also appended an SSH public key to /root/.ssh/authorized_keys, giving persistent remote access.
- The malicious behavior was hidden behind many layers of legitimate-looking functions and module indirection.
- The attacker registered the domain ether-sign.com (registered Oct 15, 2024) and hosted the endpoint on an IP at 88[.]99[.]95[.]50 (Hetzner Online).
- Identified malicious packages include ethers-mew, ethers-web3, ethers-6, ethers-eth, ethers-aaa, ethers-audit, and ethers-test.
- Packages and author accounts were short-lived and appear to have been removed shortly after publication.
MITRE Techniques
- [T1003] Credential Dumping – Exfiltration of Ethereum private keys from the victim’s machine. [‘exfiltration of Ethereum private keys from the victim’s machine.’]
- [T1203] SSH Hijacking – Modifying the root user’s authorized_keys file to grant the attacker SSH access. [‘writing the attacker’s SSH public key in the root user’s authorized_keys file.’]
- [T1195] Supply Chain Compromise – Trojanizing npm packages that mimic the legitimate ethers library to distribute malicious code. [‘Trojanizing legitimate npm packages to distribute malware.’]
- [T1071] Command and Control – Sending stolen keys to a remote server at ether-sign.com via HTTP POST. [‘Sending private keys to a remote server (ether-sign.com).’]
Indicators of Compromise
- [Domain] Exfiltration endpoint – ether-sign[.]com
- [IP address] Hosting of malicious endpoint – 88[.]99[.]95[.]50
- [Npm packages] Malicious package names – ethers-mew, ethers-web3, and 5 more packages
- [SSH username/machine] Attacker identity in key comment – cp@DESKTOP-7BQLEIP
- [SSH public key] Attacker public key added to authorized_keys – ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQC8v6v3… (truncated)
Phylum’s automated risk detector recently flagged several npm packages that appeared to be legitimate forks of the widely used ethers library but contained malicious logic. Instead of exploiting install-time hooks, these packages required a developer to instantiate or otherwise use the library, at which point the trojanized code executed a chain of calls that ultimately stole private keys and granted the attacker SSH access. The malicious flow begins in modified wallet code: creating a Wallet instance triggers an added check that calls checkAddress, which forwards to checkServer and posts the supplied key to a remote endpoint. That endpoint is hosted at ether-sign[.]com and was observed to be registered on October 15, 2024; the hosting IP was seen as 88[.]99[.]95[.]50 (Hetzner Online).
The attackers layered their modifications to blend in with the existing ethers module structure. Small, plausible-looking changes were introduced across multiple files: wallet/wallet.js was modified to call a checkAddress function on string keys; transaction/index.js exported new functions including checkAddress and superSignKey; transaction/address.js and utils/index.js were extended to route calls to a data.js implementation; and utils/data.js implemented checkServer by issuing an axios POST to , sending the private key as the payload. Because the check was invoked when a developer supplied a private key string to the Wallet constructor, a routine usage pattern (new Wallet(privateKey)) was sufficient to exfiltrate sensitive material.
Beyond key exfiltration, the attacker inserted a mechanism to gain persistent remote access. The signing-key constructor was altered to call superSignKey(), which appends an attacker-controlled SSH public key to /root/.ssh/authorized_keys. The public key is returned by an overloaded getAddress(“signatureKey”) path; when that special string is passed, getAddress returns a hardcoded ssh-rsa key (commented as cp@DESKTOP-7BQLEIP). This dual capability—stealing Ethereum private keys and planting an SSH key—means victims not only lose control of crypto assets but may also have their host machines entirely compromised.
The campaign used multiple similarly named packages to increase the chance of developer confusion, including ethers-mew (the most complete with SSH-writing behavior), ethers-web3, ethers-6, ethers-eth, ethers-aaa, ethers-audit, and ethers-test. Many of these packages and the associated user accounts were short-lived and were deleted or removed soon after publication, suggesting the attacker tested variants before or immediately after release. The trojanized code deliberately used benign-sounding function and variable names—checkAddress, checkServer, superSignKey—and leveraged the modular layout of the original library to obscure the malicious intent across several files, making manual detection harder.
Technical reviewers comparing legitimate [email protected] with the trojanized [email protected] traced the exact diffs: wallet/wallet.js gained an import and a conditional call to checkAddress, transaction/index.js exported checkAddress and superSignKey, address.js introduced checkAddress and superSignKey implementations that relied on utils and fs, utils/index.js re-exported checkServer, and data.js implemented checkServer using axios.post to the ether-sign endpoint. The BaseWallet constructor also had its assertion modified so that an extra checkAddress call could be performed on the provided key object. These changes are a clear example of supply-chain abuse that blends small code edits with plausible naming to hide malicious behavior.
In summary, this incident demonstrates a sophisticated supply-chain attack that combined targeted exfiltration of cryptographic material with host takeover via SSH key insertion. Developers who import libraries should verify package provenance, prefer pinned and audited dependencies, and scan new or unfamiliar packages with automated tools. The identified IoCs include the domain ether-sign[.]com, hosting IP 88[.]99[.]95[.]50, the attacker SSH key (comment cp@DESKTOP-7BQLEIP), and a set of malicious npm package names. These indicators, along with awareness of the described code paths, can help defenders detect and mitigate similar attempts in the future.
Read more: https://blog.phylum.io/trojanized-ethers-forks-on-npm-attempting-to-steal-ethereum-private-keys/