Secure by default solution for dependency confusion

Cover image

Regardless if you call it dependency confusion, substitution attacks or namespace confusion it’s all about injecting non-intended packages. Dependency confusion occurs when a user or system is tricked into pulling a package version from a public registry, instead of the intended package of the same name from a private registry.

And it has been the new supply chain attack that everyone has been discussing in 2021.

The question that everyone has been asking: How do you defend your supply chain from this issue? There’s been plenty of suggestions, including from us at Bytesafe:

  • Use of scoped packages and claiming the namespace in the public registry.
  • Using vetted registries, with only approved packages (Firewall registries).

Both these suggestions have merit, but they have one flaw. They require additional configuration and actions from the users to be secure.

We know that any solution that requires users to opt-in and make their own configurations will never be safe enough. For us, it was clear from the start that our solution should be safe out of the box.

We are happy to introduce our safe by default solution for Dependency Confusion: Internal packages.

For more information on the dependency confusion concept, see our previous post from February 2021

How to avoid dependency confusion

One of the primary goals was to design a solution that does not rely on complex user configuration.

The solution in short:

  • Package versions published, pushed or uploaded to an internal registry will automatically be flagged as internal
  • Fetching new versions of internal packages from upstream sources, will only consider upstreams containing internal versions of the same package

It’s as simple as that. Packages flagged as internal will automatically be protected from dependency confusion.

Packages without the internal flag will function as they always have, with full access to public upstreams.

Users can continue to use Bytesafe registries for both public and private packages, enjoying the benefits of a single source of truth for all package dependencies. While simultaneously being fully protected from dependency confusion.

And the best part, all the complex logic behind it is handled by Bytesafe, instead of being pushed on to our users.

Working with internal packages

From a user standpoint the solution couldn’t be simpler: Internal packages are prevented from being fetched from external upstreams by mistake.

Let’s have a look at how that works in practice.

Internal registries & packages

Any registry in Bytesafe can now be flagged as internal. This is enabled by default when creating any new registry to make the solution as low-touch as possible.

Any versions pushed to an internal registry will automatically be flagged as an internal version.

Example: Publish private packages to a private registry, to be shared and available to other team members or systems:

$ npm --registry 'https://workspace.bytesafe.dev/r/your-internal-registry/' publish

...

+ your-internal-package@4.5.6

With the registry destination flagged as internal the version will be flagged internal as well.

example-internal-package-in-bytesafe

Protection during dependency resolution (npm install)

The core functionality of internal packages is evident when resolving dependencies from upstream. This is typically the case when using npm install to install dependencies for a project and npm attempts to fetch all available versions. Or when using bytesafe pull or Bytesafe web to fetch new versions from upstream sources.

Any attempt to fetch new versions of internal packages from upstreams will only use upstreams that contain other internal versions of the packages as valid sources. All other sources will be ignored for the purpose of this action.

Bytesafe users can securely install any internal version from their registries. Without ever having to worry about the possibility of the package being replaced with a malicious package from any external registry.

Example: Using a Bytesafe private registry together with registry.npmjs.org as an upstream for public packages:

public registry will not be considered for internal package
publish - internal package
install - internal package
install - internal package
registry.npmjs.org
Internal registry
User A
Team B
System C
  • Package published to the private registry will be flagged internal
  • Install of internal package by other users / systems will never fetch versions from registry.npmjs.org as it does not contain internal versions
  • Installing any public package will work as normal, with registry.npmjs.org as a valid upstream

Internal registries does not equal private only (it can also contain public packages)

One important distinction is that registries flagged internal are not only for private packages.

Public package versions (like any package fetched from registry.npmjs.org) will be completely unaffected by the addition of internal packages and registries.

Dependency confusion Term coined for the confusion of package managers on what package version to pull into your project, from what source, when faced with multiple options.

Getting started - protecting internal packages

New workspaces and registries - No action required

The internal packages feature is active by default. New registries are created with the internal flag enabled.

All package versions pushed to internal registries will automatically be flagged internal (and be protected from dependency confusion).

For existing workspaces and registries

Protecting existing registries and packages is as simple as:

  1. Enable the internal flag for your registry
  2. Republish the latest version of all internal packages

Done! All the complexity when fetching packages will be handled securely by Bytesafe.

From now on, fetches of internal packages will only consider upstreams containing internal flagged versions of the package.

Upstream issues - additional layer of defence against supply chain attacks

Bytesafe also detects upstream configuration issues that could indicate a supply chain attack.

upstream-issue

Upstream issues are opened when a package version is found in multiple external upstreams, with non-matching contents. Issues trigger notifications, warning you of a potential dependency confusion attack.

Visit docs.bytesafe.dev for more details

Most users will not require any additional configuration to be protected. But for users that require advanced configurations, like how to configure a trusted source outside of a Bytesafe workspace, make sure to check out the documentation on internal packages.

Want to try it out immediately? Login to your existing workspace.

New user? Sign up and create a new workspace for you and your team! No commitment - Bytesafe is always free to try!
Security is never easy. Let us guide you through the jungle!

We’ll keep you up to date on supply chain security and send you the latest information.