MAL-2026-16154

    Dashboard / Malicious Package / MAL-2026-16154

    MAL-2026-16154

    Published: 14 Sept 2026Last Modified: 30 Sept 2026

    Summary: Malicious code in pino-ulid (npm)

    Details: The npm package pino-ulid is named like a ULID generator, but it is a remote-access trojan. On install, its package.json postinstall script runs `node dist/node/utils.js` (after checking the dist files exist with existsSync). dist/node/utils.js writes a PID lock file, sets up persistence on Windows using schtasks and reg under the name `pkg-agent`, skips machines with fewer than 4 CPUs, and then starts dist/node/payload.js as a detached child process. dist/node/payload.js (about 456 KB, SHA-256 3a9089e9db3650dd6d1584fae709022002dc34854b961abfb014a90f0a7c6a50) is the agent. It connects to a hardcoded WebSocket command-and-control (C2) server. The C2 URL is hidden in dist/agent/config.js as a base64 string XORed with the 8-byte key [90,60,126,18,159,75,109,138], which decodes to ws://95.216.232.162:8010/ (HTTP form http://95.216.232.162:8010/, 15000 ms heartbeat). The agent sends a machine id and system info to the C2, reconnects if the link drops, and supports a `deploy_binary` command: the C2 sends base64 content that the agent writes to disk and runs, replacing itself and setting up persistence again. This gives the attacker remote code execution on the victim machine. The ULID name and description are just cover for the bundled agent that runs on install. Source: amazon-inspector (ade54621ac8726adc77fa29c4176808cdf82d0d1f8e45c2e051a17b1fd515779) pino-ulid impersonates the popular `pino` and `ulid` packages (homepage points at github.com/ulid/javascript) and ships a genuine ULID code path as cover. The package.json `postinstall` hook runs `node dist/node/utils.js`, which spawns `dist/node/payload.js` detached with stdio ignored and unref'd, gated by a minimum CPU-count check (sandbox evasion) and a prior-install check against schtasks / HKCU Run / launchd / systemd / autostart. The bundled 466 KB `dist/node/payload.js` self-labels as `Package-bin Agent - Bundled payload`, includes the `ws` client, decodes a hardcoded configuration via `Buffer.from(enc, 'base64')`, derives a per-host id via `getSystemMachineId`/`defaultAgentId`, and opens a WebSocket control channel. Its `ws.on('message',...)` handler reaches `execSync`/`spawnSync` sinks and writes attacker-supplied `task.contentBase64` bytes to disk via `writeFile`, providing remote shell execution and arbitrary file drop on the installer's host. The agent installs cross-platform boot persistence: a systemd user unit at `~/.config/systemd/user/pkg-agent.service` and/or `~/.config/autostart/pkg-agent.desktop` on Linux, `~/Library/LaunchAgents/com.launchkeeper.pkg-agent.plist` on macOS, and a Task Scheduler entry plus `HKCU\Software\Microsoft\Windows\CurrentVersion\Run` value `pkg-agent` on Windows. Running `npm install pino-ulid` installs a persistent remotely-controlled agent unrelated to the advertised ULID functionality.

    Affected packages

    Package

    Name: pino-ulid

    Purl: pkg:npm/pino-ulid

    Affected ranges

    Type: SEMVER

    Events:

    Introduced- 0
    Fixed -None

    Affected versions

    2.12.3
    2.12.2