Safeguard
Supply Chain Attacks

npm package aliasing: the dependency confusion attack surface most teams never scan

npm's alias@npm:target syntax lets an attacker capture a name that doesn't even exist yet on the registry — widening dependency confusion past simple squatting.

Safeguard Research Team
Research
6 min read

In February 2021, independent researcher Alex Birsan collected more than $130,000 in bug bounties from Apple, Microsoft, PayPal, Shopify, Netflix, Uber, and other companies by publishing public npm and PyPI packages that shared names with internal libraries — a technique he named dependency confusion. The fix most teams reached for was straightforward: scope your internal package names, or squat your own names on the public registry so nobody else can. But on November 4, 2021, Snyk researchers Nishant Jain and Mario Stathako published findings showing that npm's own aliasing syntax — npm install alias@npm:target — creates a second, quieter path into the same trap, one that doesn't require guessing an internal name at all. An attacker only needs to wait for a project to reference a target package name that doesn't exist on the public registry yet, then publish it. This post walks through how the aliasing mechanism works, why it evades the defenses teams already have in place, and what actually closes the gap.

What is npm package aliasing and why does it exist?

npm aliasing lets a package.json dependency entry use one name locally while resolving to a different package on install, via the syntax "some-alias": "npm:actual-package-name@1.0.0" in the dependencies block, or equivalently npm install some-alias@npm:actual-package-name@1.0.0 on the command line. It's a legitimate, documented npm CLI feature, commonly used to install two major versions of the same library side by side (for example, aliasing react-v17 and react-v18 to their respective real packages during a migration) or to give a long scoped name a short local handle. The npm CLI has supported this for years as a documented part of its package-spec syntax, and it works identically whether the target package already exists on the registry or not — which is the detail Snyk's research turned into an attack surface.

How does aliasing extend dependency confusion beyond name-squatting?

Snyk's Jain and Stathako demonstrated that an alias entry like "deneuve-package-private": "npm:deneuve-package-test@1.0.0" can reference a target name — deneuve-package-test — that does not yet exist on the public npm registry at all. Ordinary dependency confusion requires an attacker to guess the exact name of an existing internal package. Aliasing removes that constraint: the attacker doesn't need to guess anything, because the target name is sitting in plain sight in a public repository's package.json or in the registry's own dependency listing for that package. Once the attacker publishes a package under that exact target name, npmjs.org itself begins displaying it as a linked, seemingly legitimate dependency on the referencing package's registry page — even though, as Snyk noted, the alias "doesn't actually exist on the npmjs registry — unless someone publishes it." Any developer who manually runs npm install on that displayed name, or any tooling that resolves it independently, pulls the attacker's package.

Who actually gets exposed by this technique?

The exposure isn't limited to the original package author. Snyk's research described a scenario where a legitimate package uses an alias pointing at a private or unpublished target, and the registry's public page for that package lists the alias as if it were a real, installable dependency. Developers debugging a dependency tree, or simply exploring what a package depends on, can be misled into installing the fictitious name directly rather than through the alias mapping — at which point they get whatever the attacker chose to publish. This is distinct from classic squatting because the victim pool includes anyone who reads the dependency graph, not just build systems that auto-resolve an internal name. It also means the attack surface grows every time a maintainer adopts aliasing for version-pinning or migration convenience, since each alias introduces a new target name that is only safe as long as no one else claims it first.

How does this relate to other npm registry-trust weaknesses?

Aliasing confusion sits alongside a separate but related npm ecosystem weakness known as manifest confusion, which CSO Online covered in 2023: npm's registry accepts a manifest submitted via the publish API separately from the actual package.json bundled inside the tarball, and historically did not validate that the two matched. JFrog's security research team later found more than 800 packages with discrepancies between their published manifest and their tarball contents, with at least 18 confirmed to be intentionally exploiting the mismatch. Neither issue is a bug in the sense of memory corruption — both are trust gaps in how the registry represents a package versus what actually gets installed. Together they illustrate a pattern: npm's flexibility around naming and metadata, built for legitimate developer convenience, consistently doubles as a way to make a malicious install look ordinary.

Is this still an active attack pattern today?

Yes — dependency confusion as a category remains an active, evolving threat rather than a one-time 2021 incident. Microsoft Threat Intelligence reported on May 29, 2026 that it had identified 33 malicious npm packages published across nine organizational scopes — including names mirroring internal namespaces such as @cloudplatform-single-spa and @data-science — using dependency confusion to get installed inside real corporate environments, where they executed an obfuscated reconnaissance payload that profiled the developer's machine and phoned home to an attacker-controlled server. npm's own registry team revoked the associated publishing tokens and removed the packages within hours, but the campaign underscores that scoped-namespace confusion and aliasing-style tricks are still being actively probed against real organizations, not just described in research papers.

How should teams defend against aliasing-based confusion?

The core mitigation for classic dependency confusion — always resolving your internal package names from a private registry first, via scoped names or a registry configuration that never falls through to the public npm registry — does not fully cover aliasing, because the risk here is a human or a tool resolving a displayed target name directly rather than through the alias. Practical defenses include treating any alias target name the same way you'd treat a direct dependency for security review, auditing package.json files for npm: alias syntax during code review, and enforcing that installs go through a controlled proxy rather than ad hoc developer machines resolving names by hand. Safeguard's Package Firewall runs as an install-time proxy in front of npm and pip, evaluating every fetch — including transitive ones — for typosquatting, malware signatures, and dependency or namespace confusion, with allow/warn/block/quarantine enforcement modes and an audit trail per decision, so a name resolving unexpectedly to a public package is caught at the point of install rather than after it's already in your tree.

Never miss an update

Weekly insights on software supply chain security, delivered to your inbox.