Software supply chain attacks have become much more prevalent in recent years, particularly after the successful attack by “APT29/CozyBear” against the SolarWinds Orion application.
Malicious threat actors have recognised, if they weren’t already aware, the potential benefits of compromising a trusted dependency or component utilised by many organisations. Successfully exploiting this type of vulnerability can yield substantial rewards relative to the time and effort invested in developing the attack.
There are many ways in which a software supply chain attack can be conducted, and this insight will explore one of them – utilising Dependency Confusion.
A brief overview of Dependency Confusion
Dependency Confusion occurs when a threat actor can execute malicious code on a company’s network by “overriding” privately developed software packages. This is done by leveraging public repositories that host packages with the same name but higher version numbers.
Modern package management systems for languages such as NPM, Python, and Ruby face complex decisions when installing packages and their dependencies. These systems are designed to choose the best match, often opting for the package with the correct name and the highest version value.
For various reasons, organisations may choose not to publish their internally developed packages to public repositories, including not providing even placeholder information to secure the package name publicly. As a result, when Continuous Integration/Continuous Deployment (CI/CD) environments are not optimally configured, the risk of dependency confusion becomes a valid attack vector for organisations using these in-house developed packages.
Key requirements for Dependency Confusion
The key requirement for conducting this type of attack is to identify the names of the internally developed packages that an organisation uses and to verify that these packages are not already registered in a public repository. While this blog does not delve deeply into the various techniques for gathering such data, we have provided a list below of sources where such information can be obtained:
- package.json – For NPM packages for example, this file will also list dependencies
- JavaScript files – Public client-side JavaScript files can contain require() methods, which will list the names of dependant packages.
- Error messages – Verbose errors in applications can leak the names of used packages.
Example of Dependency Confusion
In the following steps, we provide an example of how, under default configurations, dependency confusion can occur.
In the example below, dummy packages have been created and published to a private repository. We will use the NPM package manager for JavaScript and configure a local repository for NPM to use.