Safeguard
Software Supply Chain Security

Understanding dependency confusion via npm package aliasing

npm's `npm:` alias syntax lets a trusted-looking dependency name resolve to attacker-controlled code — here's how that becomes dependency confusion, and how to detect it.

Priya Mehta
DevSecOps Engineer
7 min read

npm's npm: alias protocol lets any dependency key in package.json point to a different package entirely — "leftpad": "npm:left-pad@1.3.0" installs left-pad under the name leftpad. Since npm 6.9.0 shipped this feature in April 2019, it has been a legitimate tool for testing forks, patched builds, and side-by-side major versions. It is also a near-perfect disguise for a dependency confusion attack: the string a developer, a reviewer, or a scanner sees in the manifest is not the string that determines what code actually runs. An attacker who controls the aliased target controls execution, while everything downstream — npm ls, a pull request diff, an SBOM keyed on declared names — still shows the trusted label. This gap between logical name and resolved package is the exact mechanism behind several real npm supply chain compromises, and it is the specific pattern this post breaks down: how the alias syntax works, how it's been weaponized, and what detection actually requires.

What Is npm Package Aliasing, Exactly?

npm package aliasing is a manifest-level rename: the key in dependencies becomes an arbitrary local identifier while the value's npm: prefix specifies the actual package and version to fetch from the registry. For example:

"dependencies": {
  "internal-auth-lib": "npm:internal-auth-lib-v2@2.3.1"
}

Here, require('internal-auth-lib') resolves to code published under the completely different registry name internal-auth-lib-v2. npm added this in v6.9.0 (April 2019) specifically to let developers install two versions of the same library side by side, or swap in a fork without touching import statements across a codebase. Yarn and pnpm support equivalent syntax. The feature works exactly as designed — the risk isn't a bug, it's that the resolved identity and the displayed identity can diverge by design, and nothing in the default tooling flags that divergence.

How Does Aliasing Turn Into a Dependency Confusion Attack?

Aliasing turns into dependency confusion when the resolved target is attacker-controlled but the displayed key still reads as a trusted, internal, or well-known package. Classic dependency confusion (the pattern Alex Birsan documented in February 2021) relies on an attacker publishing a public package with the same name as a company's private, unscoped internal package, betting that a misconfigured .npmrc or missing scope resolves to the public registry first. Aliasing gives attackers a second, more direct path: instead of hoping for a resolver misconfiguration, they get a developer, a compromised CI script, or a malicious pull request to add or modify one line — "stripe-utils": "npm:stripe-ut1ls@0.0.3" — where the alias key matches an internal or well-trusted package name but the target is a typosquatted or freshly published malicious package. Anyone scanning the dependency tree by key name, anyone skimming a large package.json diff, and any allowlist-based scanner that matches on the declared name rather than the resolved target will miss it, because the label lies by design and nothing in the default npm install output distinguishes an alias from a normal entry unless you read the value carefully.

What Real-World Incidents Prove This Risk Is Not Theoretical?

This risk is not theoretical because dependency confusion — the attack class aliasing extends — has already produced named, dated breaches with public bug bounty and incident records. Birsan's February 2021 research, published under the title "Dependency Confusion: How I Hacked Into Apple, Microsoft and Dozens of Other Companies," used the underlying confusion technique (not aliasing specifically) to get code executing inside networks at PayPal, Microsoft, Apple, Netflix, Yelp, Tesla, Uber, and Shopify, earning over $130,000 in bounties across roughly 35 companies. On December 30, 2022, an attacker registered a malicious torchtriton package on PyPI matching the name of an internal PyTorch dependency; because PyPI was checked before Meta's internal index, pip install torch nightly builds pulled and executed the attacker's package on machines inside Meta and Linux Foundation infrastructure until it was pulled days later. Sonatype's 2023 State of the Software Supply Chain report logged more than 245,000 malicious open source packages discovered that year alone — more than the cumulative total from the prior four years combined — with npm consistently among the most-targeted registries given its 3.1-million-plus package count as of early 2024. Aliasing-specific abuse has surfaced in npm malware campaigns documented by security researchers, where the npm: protocol was used specifically to make a malicious package's code load under the import name of a popular, trusted library, defeating name-based allowlists in the process.

Why Do Code Reviews and Security Scanners Miss Aliased Packages?

Code reviews and scanners miss aliased packages because most tooling in the npm ecosystem was built to key on the declared dependency name, not the resolved package identity, and the two only diverge in an alias entry. A reviewer scanning a 200-line package.json diff for an added line like "chalk": "npm:chalk-fork@4.1.2" sees the familiar name chalk on the left and often stops reading before parsing the npm: target on the right — especially in an automated dependency-bump PR where 30 similar-looking lines change at once. Static SCA scanners that resolve vulnerabilities against a manifest's declared package name-and-version pairs, rather than fully resolving each npm: target through the lockfile, will report on the alias key's apparent identity and can under-report or misattribute risk on the actual installed code. Lockfiles (package-lock.json, yarn.lock) do record the true resolved target and integrity hash, which is why any detection strategy has to parse the lockfile's resolution graph rather than trust the manifest in isolation — but many CI pipelines still gate on manifest-level scans for speed, leaving exactly the window aliasing is built to exploit.

How Can Teams Detect and Block Malicious Aliasing Today?

Teams can detect and block malicious aliasing today by treating every npm: value as a distinct package identity that gets its own provenance, reputation, and vulnerability check — not by trusting the alias key. Concretely, that means: parsing package-lock.json or yarn.lock (not just package.json) to extract the actual resolved package name, version, and integrity hash behind every alias; diffing dependency changes on resolved identity so a PR that swaps express's target package triggers review even if the key name is unchanged; enforcing registry allowlists and scoped-package reservation for all internal package names to close the classic confusion vector that aliasing often piggybacks on; and requiring provenance attestation (npm's npm publish --provenance, generally available since npm 9.5, June 2023) so a resolved package's build origin can be verified independent of its name. Manual review alone doesn't scale past a handful of dependencies per PR, which is why this needs to run as an automated gate in CI rather than a checklist item.

How Safeguard Helps

Safeguard closes exactly this gap by resolving every dependency — aliased or not — down to the actual package that ships in your build, then running reachability analysis to determine whether that resolved code path is ever actually called from your application rather than just present in node_modules. Griffin AI, Safeguard's detection engine, is trained to flag alias-based masquerading patterns, typosquats, and resolution mismatches between a manifest's declared key and its npm: target before they merge. Safeguard generates and ingests SBOMs keyed on resolved package identity, not declared name, so aliasing can't create a blind spot in your vulnerability or license inventory. When a suspicious or malicious alias is found, Safeguard opens an auto-fix pull request that removes or pins the offending dependency to a verified target, so the fix ships as fast as the exploit attempt did.

Never miss an update

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