How Dependency Confusion attack works and How to prevent it

Dependency confusion is a novel type of supply chain security issue after it was first disclosed by Alex Birsan in 2021 .This attack, as the name implies, might be initiated via a perplexing dependency manager tool (npm for NodeJs, pip for Python, rubygems for Ruby) to install a malicious dependency package. 

Before we dive deep into the issue,  let’s have a look at how package manager tools pull and install packages on a workstation. The graphic below depicts the workflow when the command ‘npm install express‘ is done on a workstation.

How Package Manager Tool works

How does dependency confusion attack works?

A dependency confusion attack occurs when a dependency library is downloaded from a public registry rather than the intended private/internal registry because a malicious attacker could trick the package manager (npm for NodeJs, pip for Python, rubygems for ruby) into downloading the malicious one from the public repository he controls.

To deceive the package manager tools into downloading the malicious package from the public registry, the attacker must meet the following prerequisites.

  1. Find the name of a package that the victims wants to install
  2. Create an identically named package and publish it under the public or default registry.
  3. Assign the package with a higher version number to trick the package manager tool to download it from public repo.

Occasionally, if the private registry is misconfigured. As a result of this misconfiguration, a developer’s machine or a server may be erroneously configured to collect packages from the public registry. For example, if a developer tries to install an internal package at home but does not have access to the private registry where valid packages are hosted, the package manager will try to see if a package with the same name is hosted under a public registry and use it

The diagram below depicts how Confusion Dependency exploits are initiated.

How to prevent dependency confusion attacks?

There is no silver bullet to prevent dependency confusion as this kind of attack is a consequence of an inherent design flaw in the default configuration of many package manager tools.  Instead, there are a number best practices that we could follow to help us to mitigate the potential risks.

Here are a number of best practices and mitigation method we could use

1. Prevent at the source: Reserve the package name in public registry
2. Prevent at the source: Reserve a company namespace or scope in public registry
3. Prevent at configuration: Unitize namespace and scope to ensure private registry is used
4. Prevent at configuration: Use version pinning to explicitly declare package version
5. Prevent at action: Verify package source before installing
6. Continuous Monitoring: Monitor the public registry and get alerted

Prevent at the Source: Reserve the package name in public registry

By claiming all the internal package names in the public or default registry, the will prevent a malicious attacker from hijacking the same package names and publish malicious pages under the public registry. 

This method prevents a malicious package with the same name as the internal package name from being published under the public registry at the source, which is a highly effective and reliable way to prevent dependency confusion regardless of whether there is a server misconfiguration or human errors when pulling a dependency package.

Prevent at the Source: Reserve a company namespace or scope 

Another way to prevent dependency confusion at the source is to reserve a company namespace or scope in the registry. A scope or namespace enables you to create a package with the same name as another user’s or organization’s package without conflict. This means that an organization can claim many package names under a special namespace, but an attacker will not be able to create packages under this scope because only the owner of the scope could publish packages under this scope.

The potential disadvantages are as follows: a) you must modify your manifest package management files to include the namespace or scope. b) If the namespace or scope was ignored during manual package installation, a developer might nonetheless fetch a harmful package.

Prevent at Configuration:  Unitize namespace and scope to ensure private registry is used (Client Side Control)

Some package managers allow for namespaces or other prefixes, which can be used to ensure that internal dependencies are pulled from private repositories (eg, Github) or registry defined with the appropriate prefix/scope.

Here’s an example where the dependency is explicitly stated to be pulled from a Github repository.

Prevent at configuration: Version pinning 

Dependency version pinning is a client side control method by specifying the version of a package that application will use. By setting the dependency version, it  ensures the package managers will not pull and install dependencies from the public registry in case an malicious attacker sets a higher version number for the malicious package with the identical internal package name.

There are some downsides of using version pinning.  Sometimes, if you use version pinning in the package management manifest file, for example, package.json, it will protect you against a very small portion of your direct dependency packages. The transitive dependency could still be vulnerable to dependency confusion. You should use the version pinning under the lock file, for example, package-lock.json, this allows you to lock both direct and transitive dependency into a/several specific versions.

Prevent at action: Verify package source before install

It would be very beneficial if developers could validate the package source before installing a new package or upgrading it to a higher version to avoid human errors. Take npm for example, you could use the npm view command to view the package before installing. Below is an result when running command npm view express and it tells the source of the package

Continuous Monitoring: Monitor the public registry and get alerted

I used to write an automation tool to combat package typosquatting attacks by sending HTTP requests to public registries to check for typosquatting packages. An alert is sent to our organization when a potential typosquatting package is detected. I believe we could create a similar tool and run it at regular intervals to be alerted when your internal package names are published in public registries.

Conclusion

Defending against dependency confusion attacks is a critical component of software supply chain security. Many regulations and countermeasures could be implemented at the source or configuration level by your company. Because imposed countermeasures cannot always prevent human errors, it is critical to train your engineers to exercise cautions and follow the aforementioned best practice  when upgrading or adding a package.

Leave a Reply

Your email address will not be published. Required fields are marked *