Tillatelsesslipp: npm-pakke skjuler sky- og systemtrusler

Tillatelsesslipp: En npm-forsidehistorie om «autorisert forskning» som skjuler skymetadata-undersøkelser og SYSTEM-persistens

TL; DR

Between 2026-06-15 and 2026-06-16 a single npm publisher pushed six packages — 26 versions in all — that run an install-time script on every npm install. Each package ships a README declaring it a "benign" HackerOne / GitHub Bug Bounty research artifact that "never" touches credential values and "performs no persistence." The code does not match the disclaimer. On Linux CI runners the install hook fingerprints the environment and probes a cloud instance-metadata endpoint; on Windows it requests elevation, runs as SYSTEM, and opens a command channel to an external host. The one indicator to search for now is the C2 host 173.255.233[.]239. Severity: høyBerørt økosystem: NPM. Names blend into continuous-integration dependency noise (metrics-pipeline-d8k2, event-metrics-q3x7, pkg-telemetry-r4f9, and three siblings).

Angrepet: Hvordan det fungerer

Every package in the cluster is built the same way. The pakke.json wires the same command into two lifecycle hooks:

{   "scripts": {     "preinstall": "node run.js",     "postinstall": "node run.js"   } }

Running on both preinstall and postinstall means the payload fires whether or not later install steps fail. run.js itself is a ten-line platform dispatcher:

// Platform dispatcher — runs beaconNN.js on Windows, beacon_linux.js on Linux. // GitHub Bug Bounty authorized research. Contact: nicholas@curran.tech 'use strict'; const { execFileSync } = require('child_process'); const path = require('path'); const node = process.execPath; const script = process.platform === 'win32'   ? path.join(__dirname, 'beacon34.js')   : path.join(__dirname, 'beacon_linux.js'); try { execFileSync(node, [script], { stdio: 'inherit', timeout: 90000 }); } catch (e) {}

The behavior then forks by operating system. All six packages carry the same two pieces — run.js and the platform beacons — so they are interchangeable droppers rather than six distinct tools. The only meaningful variation between them is publish cadence: four names shipped once, while two were re-released every 30–60 minutes for hours, which keeps a freshly published version in front of installers and resolvers even as older ones are pulled.

På Linux (beacon_linux.js) the script profiles where it is running. It enumerates the names of environment variables, reads files under / proc, checks for docker.sock, og kjører vertsnavn og whoami. It then issues an HTTP request to the AWS container instance-metadata endpoint 169.254.170[.]2 — the link-local address an ECS task queries to obtain its own configuration and short-lived role credentials (IMDS, the instance metadata service). The results are POSTed to the campaign’s collector at 173.255.233[.]239.

På Windows (beacon34.js / beacon18.js) the package does considerably more than profile its host. The flagged code adds a registry key under the ms-innstillinger handler with a DelegateExecute value — a known user-account-control bypass that lets a launched process run elevated without a prompt. It invokes PowerShell with -ExecutionPolicy Bypass og Anrop-uttrykk, executes in the NT MYNDIGHET\SYSTEM context, and polls an external host for commands. The Windows command channel runs over a Cloudflare tunnel, diameter-coins-limitations-parents.trycloudflare[.]com:443, falling back to 173.255.233[.]239:443, using three endpoints: /c2/poll to fetch a command, /c2/out to return output, /c2/eof å lukke.

What’s new here: the disclaimer as camouflage

The novel element is not the payload — install-hook reconnaissance and Windows elevation are both well documented. It is the cover story. Each package carries a README that reads as a responsible-disclosure artifact:

# @ncurran/sandbox-recon-880538 — authorized npm-sandbox security research

Dette er en godartet package published under the author’s own `@ncurran` scope as part of an authorized HackerOne / GitHub Bug Bounty engagement (npm is in scope).

On install it inspects its own execution environment … environment-variable

key names only … checks whether well-known cloud metadata endpoints er reachable … It reports only status codes, response lengths, and hashes — aldri any credential, token value, or third-party data. It performs no persistence, no lateral movement, and no destructive action.

Three claims in that text are contradicted by the shipped code. The README says “no persistence,” but the Windows beacon writes a registry-based elevation key. It says “never any credential, token value,” but the Windows path runs arbitrary fetched commands as SYSTEM, which places no such limit on what is read or returned. It even names a package — @ncurran/sandbox-recon-880538 — that is not the one it ships in, indicating the README is a reused template rather than a description of the artifact in hand. A consent disclaimer in a package a victim never agreed to install grants no consent. The classification here is malicious regardless of the wording. The disclaimer also has a quieter target: an automated triage step that reads package text for reassuring signals — “benign,” “authorized,” a named program, a contact email — can be nudged toward a safe verdict by prose that the payload contradicts. The lesson holds for human and machine reviewers alike: weigh the install-time behavior, not the README’s self-description.

Tidslinje

All packages appeared inside a 24-hour window. The four single-version names landed first, followed by two packages that were re-published every 30–60 minutes.

Dato (UTC) Event
2026-06-15 18:32 First package published — npm:pkg-telemetry-r4f9@1.0.0
2026-06-15 19:50 npm:runtime-metrics-w7k2@1.0.0 publisert
2026-06-15 20:14 npm:build-tracker-n5p1@1.0.0 publisert
2026-06-15 20:35 npm:npm-sandbox-ping-r9t2@1.0.0 publisert
2026-06-15 21:09–22:42 npm:event-metrics-q3x7 publisert 1.0.0 → 1.0.8 (9 versions)
2026-06-15 23:40 → 2026-06-16 04:40 npm:metrics-pipeline-d8k2 publisert 1.0.0 → 1.0.10 (11 versions)
2026-06-16 Cluster identified and classified malicious; several tarballs already returning 404 at the registry (ongoing)

The campaign is recent and the takedown is still settling: at analysis time some versions resolved at the registry and others did not. Treat all 26 versions as compromised.

Indikatorer for kompromiss

Nettsidepakker

Økosystem Pakke versjoner status
NPM metrics-pipeline-d8k2 1.0.0 – 1.0.10 skadelig
NPM event-metrics-q3x7 1.0.0 – 1.0.8 skadelig
NPM runtime-metrics-w7k2 1.0.0 skadelig
NPM build-tracker-n5p1 1.0.0 skadelig
NPM npm-sandbox-ping-r9t2 1.0.0 skadelig
NPM pkg-telemetry-r4f9 1.0.0 skadelig

Network

typen Indikator Merknader
IP 173.255.233[.]239 C2 collector; Linux recon POST and Windows fallback :443
Domene diameter-coins-limitations-parents.trycloudflare[.]com Windows command channel over a Cloudflare tunnel, :443
URI path /c2/poll, /c2/out, /c2/eof Windows command poll / output / close
IP 169.254.170[.]2 AWS ECS instance-metadata endpoint probed from the install hook

Behavioral

Signal Tekniske beskrivelser
Install hooks preinstall og postinstall both run node run.js
Platform dispatch run.js går beacon_linux.js on Linux, beacon34.js / beacon18.js på Windows
Linux recon Enumerates env-var key names, reads /proc, sjekker docker.sock, løper hostname / whoami, probes IMDS
Windows elevation ms-settings DelegateExecute registry UAC bypass; PowerShell -ExecutionPolicy Bypass + Invoke-Expression; runs as SYSTEM
Disguise README claims "benign" "authorized" research and "no persistence"; references a package name it does not ship in

Attribusjon og observert atferd

We describe the publisher by its signals only and do not assert the identity of any person behind the account.

  • Signals catalog. All six packages were published by the same npm account, npmresearch8847, with the stated email npmresearch8847@web-library.net (email and SCM verification both absent; we have not verified ownership). The READMEs publish under an @ncurran scope and give a contact of nicholas@curran.techog run.js points at the repository github.com/ncurran/npm-sandbox-research`. The six packages share an identical run.js dispatcher, a common beacon_linux.js recon stage, and the single collector host 173.255.233[.]239`. The naming scheme is consistent: a generic CI-sounding stem (beregninger, telemetri, build-tracker, sandbox-ping) plus a short random suffix.
  • Tillit. The six packages appear to be one campaign on the strength of the shared dispatcher, recon stage, and C2 host. The “authorized research” framing appears consistent across all six READMEs. We have not been able to confirm that any bug-bounty program authorized this activity, and the disclaimer’s claims do not match the shipped code.
  • Observed capability. The payload exercises four capability classes: install-hook code execution on both forhåndsinstallering og etterinstallasjon; host and CI-environment reconnaissance with egress to an external collector; cloud instance-metadata reachability probing from the install context; and, on Windows, local privilege escalation, execution as SYSTEM, and a fetch-and-run command loop over an external channel. The Windows command loop is a remote-control capability: it polls for instructions and returns their output.

Impact

The exposure is highest for automated build environments. An npm install in CI runs the lifecycle hooks with whatever identity the runner holds; on a cloud runner that identity often includes a reachable metadata endpoint and a role credential. The address the Linux beacon probes, 169.254.170[.]2, is the AWS ECS task-metadata endpoint: a task that can reach it can usually also retrieve its task role’s temporary credentials from the same link-local service. A reachability check from inside an install script is the step that precedes pulling those credentials, so any runner that ran the hook and could reach that endpoint should be treated as having had its task role exposed. On a Windows developer or build host the payload requests elevation and opens a command channel, which broadens the exposure from a single profile-and-egress to interactive remote control.

We were unable to obtain reliable download counts for the malicious versions before takedown, so we do not estimate victim numbers. The rapid re-publishing of two of the packages — eleven and nine versions in hours — kept fresh artifacts in front of installers and resolvers while older versions were being removed.

Fremvoksende mønstre

This cluster is an example of a label being used as cover. “Authorized research,” “bug bounty,” and “sandbox testing” are increasingly attached to packages whose install scripts do more than profile a host. The framing trades on a reviewer’s hesitation to act against something that announces itself as sanctioned. It pairs with a second familiar tactic: package names engineered to look like internal CI tooling so they slip past a quick glance at a dependency tree. The combination is what makes the pattern worth watching — a name that reads as infrastructure plumbing, wrapped in prose that reads as a sanctioned test, fronting an install hook that escalates on one operating system and probes cloud credentials on the other. Neither the disclaimer nor the bland name changes what the code does on install, and a triage process that weighs either of them as mitigating evidence will reach the wrong verdict.

Hva forsvarere bør gjøre

  • Search lockfiles and install logs for the six package names; treat any match as an incident, not a warning.
  • Block and alert on outbound traffic to 173.255.233[.]239 og til *.trycloudflare[.]com hosts from build infrastructure.
  • Hunt for install-time HTTP requests to instance-metadata addresses (169.254.170.2, 169.254.169.254) originating from package managers in CI.
  • Rotate any cloud role credentials and tokens that were reachable from a runner that installed an affected version.
  • Audit forhåndsinstallering/etterinstallasjon scripts in your dependency set; a lifecycle hook that runs a second script file deserves a read.
  • On Windows endpoints, hunt for new DelegateExecute values written under the ms-innstillinger shell-handler key — the elevation primitive this payload uses and a reliable signal independent of the package name.
  • Pin and review lockfiles, and disable install scripts (npm install –ignore-scripts) in CI where your build does not require them.
  • Treat “authorized research” or “benign” disclaimers inside an install script as untrusted text, not as a reason to allow the script.

A package that announces good intentions in prose and requests SYSTEM in code should be judged on the code.

sca-tools-programvare-verktøy for komposisjonsanalyse
Prioriter, utbedre og sikre programvarerisikoene dine
Få din gratis konto.
Ingen kredittkort kreves.

Sikre programvareutviklingen og -leveringen din

med Xygeni-produktpakken