Safeguard
Supply Chain•

Do npm scopes stop dependency confusion and name collisions?

Scopes give each user or organization its own npm namespace, preventing name collisions. Learn to use them for internal packages and where they fall short.

Safeguard Security Team
3 min read

Scopes help a lot, but they are not a complete defense. An npm scope is a namespace owned by a user or organization, so a scoped internal package cannot be claimed by an outsider under the same scope. It does not protect unscoped names or bad registry configuration.

What a scope is

The npm documentation says that when you sign up for an account or create an organization, you are granted a scope matching that name. A scoped package name carries the scope before a slash, for example @acme/utils, where the scope is everything between the at sign and the slash.

A scope lets different owners use the same package name without conflict. Two organizations can each have a package called utils, as long as they sit under different scopes.

The docs also state some defaults: unscoped packages are always public, private packages are always scoped, and scoped packages are private by default. You must pass a flag when publishing to make a scoped package public.

Why this matters for internal packages

Dependency confusion happens when a build asks for an internal package name and the client ends up fetching a public package with the same name. If your internal packages are unscoped, anyone can register that name publicly, possibly with a higher version number.

If your internal packages live under your own scope, the public name @yourcompany/utils is controlled by you. Nobody else can publish under that scope on the public registry.

How to apply it

  1. Move internal packages under a scope you own. Register the organization name on the public registry even if you never publish there, so nobody else can take it.
  2. Map the scope to your private registry in your npm configuration, so requests for that scope go to the private source.
  3. Avoid unscoped internal names. If you must keep some, reserve those names on the public registry with a placeholder or document why not.
  4. Commit the registry mapping alongside the project so every developer and CI job resolves the same way.
  5. Check the lockfile for resolved URLs that point somewhere unexpected for your scoped packages.

Where scopes fall short

  • Third party unscoped packages. Most popular packages are unscoped, and typo or lookalike names exist at that level.
  • Misconfiguration. If a scope is not mapped, a request may go to the default registry. That is a failure of setup, not of scopes.
  • Account takeover. Scope ownership depends on account security. Use strong authentication for every account that can publish.
  • Copycat scopes. An outsider can register a scope that looks like yours. Be careful that the scope in a dependency is spelled exactly right.

A quick audit

List every dependency in your manifests whose name looks internal. For each, answer: is it scoped, is the scope mapped to the private registry, and is the public scope reserved? Any no is a to-do.

Safeguard scans dependencies and flags packages for review, which helps with the last point: finding names that look wrong. Treat flags as prompts for a person to check.

Quick check

Are scoped packages always private?

They are private by default, but you can publish them as public with a flag, according to the npm docs.

Does using a scope make my build immune to confusion attacks?

No. Unscoped dependencies and a missing registry mapping can still send requests to the wrong place.

Sources

Last reviewed: 19 October 2026.

Never miss an update

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

Self-healing security runs on Safeguard.

Your first fix PR is minutes away.

No sales call required, even your agent can complete the purchase over MCP.