Safeguard
Supply Chain•

Tabletop script: your internal package name shows up on npm

A 45 minute tabletop script for dependency confusion: an internal package name appears on a public registry. Scope, containment and registry controls.

Safeguard Security Team
4 min read

A dependency confusion tabletop starts when someone finds your private package name on a public registry. This 45 minute script tests whether you can tell which builds resolved the public copy, what it could have run, and which registry settings would have prevented it.

The mechanism in plain words

Many teams publish internal packages to a private registry under a short name. If a build tool is allowed to look at both a private and a public source, and the public one has the same name with a higher version, the tool may prefer the public copy. An attacker who learns an internal name can register it publicly. SLSA lists using a compromised dependency as a build and runtime threat (D), and the registry controls you set decide how exposed you are.

Use a fictional package, acme-billing-core, with the premise that someone published a public version 99.0.0 yesterday.

Setup

  • Facilitator, scribe, a platform engineer who owns the package registry, two application developers, a security lead.
  • No handouts. See what the team can find.

Injects

Inject 1, minute 5. A developer sees acme-billing-core on a public registry, published a day ago by an unknown account, with a postinstall script.

Ask:

  • Who confirms this is not ours?
  • Which projects list this name? How do you search lockfiles and manifests?
  • Which registry does each build use, and in what order?

Inject 2, minute 18. CI logs show three builds last night fetched version 99.0.0 from the public registry.

Ask:

  • What did the install script have access to on those runners?
  • Were any artifacts from those builds deployed?
  • Which credentials do you rotate, and which artifacts do you rebuild?

Inject 3, minute 32. Leadership asks how you will make sure it cannot happen again.

Ask:

  • Can the build restrict internal names to the private source only?
  • Do you reserve your internal names on the public registry or use a scoped namespace?
  • Is there an alert when a new public package matches an internal name?

Prevention options to compare

ApproachStrengthCost
Scoped or namespaced internal namesClear ownershipRename effort
Registry proxy that routes internal names only to privateStrong, centralSetup and upkeep
Lockfiles with integrity hashes, installed from lockfile in CIStops new resolutionNeeds discipline
Reserving names on public registriesCheap defenceEasy to miss one

Package managers differ in how they pick between sources, so confirm behaviour for each ecosystem you use in its own documentation. Our guides on Maven repository order and Composer canonical repositories show two examples.

Debrief

Write down the three most valuable fixes and put them into an after-action report. A quick win is a scan of every manifest to list internal names, which doubles as your reservation list.

Safeguard provides SBOM and dependency scanning that lists what your projects resolve, and policies and gates for new dependencies. Try a free scan.

Try it yourself

Click through it at your own pace, or open it full screen. Find where a package comes from in the inventory and ask whether yours would show the source registry.

Quick check

Is renaming internal packages worth it?

Scoped names are one of the cleaner fixes because ownership is built in, but a proxy rule can reach a similar result with less code churn.

Does a lockfile fully protect us?

It protects builds that install from it with integrity checks. Anything that resolves fresh, such as a new project or an update, still needs registry rules.

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.