RCE via Dependency Confusion Attack
Written by Sagiv Michael on
RCE via Dependency Confusion Attack
Written by Sagiv Michael on
Introduction
Efficiency and productivity are highly valued in the fast-paced software development world. Developers who work on complex projects require accessible and dependable external libraries, frameworks, and tools. Package managers like NPM (Node.js), PyPI (Python), and RubyGems (Ruby) simplify and streamline the development process across programming languages.
In this article, we will discuss a critical security vulnerability related to the dependencies of a software project and how it can potentially lead to remote code execution. We will explore its implications on software development and how developers can mitigate this risk effectively.
What is a Dependency Confusion Attack?
Dependency Confusion, also called dependency hijacking or substitution attacks, is a serious vulnerability affecting organizations that use package managers. Attackers exploit it when developers unknowingly install malicious packages, which can cause security breaches, data leaks, or even arbitrary code execution.
The root cause of this attack vector lies in how some package managers handle the resolution of dependencies. In a typical case, when developers list a dependency in a project file (for example, package.json for NPM), the package manager fetches it either from the official public repository or from the organization’s private registry. As a result, the source depends on how the project is configured.y linked to the organization.
However, attackers can exploit the fact that some package managers prioritize the public repository over private ones when resolving package names. They can create a malicious package with the same name as an internal package used within the organization. The package manager first checks the public repository for the package. In that case, it will unknowingly download the attacker’s malicious version, even if a legitimate version is in the organization’s private registry.
Subsequently, it creates “dependency confusion,” where the package manager installs the malicious package, potentially leading to disastrous consequences.
The attacker could use this opportunity to introduce backdoors, malware, or other harmful code into the organization’s software.

Explanation of The Attack
To better understand Dependency Confusion as an attack vector, we will share a real-world scenario from a penetration test. In this case, we used the technique to achieve Remote Code Execution (RCE) on a targeted system.
As a starting point, we studied the web application and learned about its purpose, business logic, and underlying technologies. This in-depth analysis gave us a comprehensive understanding of the website’s structure and potential vulnerabilities.
We conducted an OSINT (Open-source intelligence) activity, an essential step in gathering valuable information from publicly available sources. During OSINT, we discovered a critical finding: an exposed package.json file in the client-side resources. This file revealed important details about the applications and modules used by the web application.
The exposure of the package.json file created a perfect opportunity for a Dependency Confusion attack, and we quickly realized its potential implications.

When examining the file, we found that the web application relied on an internal dependency (package name altered for privacy). To confirm this, we searched for it on the official NPM registry, but it was not publicly available. This indicated that the organization relied on its private registry to host and manage this specific package.
Recognizing the significance of this finding, we proceeded to conduct a Proof-of-Concept (PoC) to test and execute the attack thoroughly. Our objective was to demonstrate the potential consequences of a Dependency Confusion attack to execute arbitrary code (Remote Code Execution) on the targeted system.
Proof of Concept (PoC)
To build a cross-platform Proof-of-Concept (PoC) for the Dependency Confusion attack, we combined PowerShell, Bash, and JavaScript. By using HTTPS over port 443, we ensured the PoC bypassed the company’s firewall rules, since this protocol is commonly allowed.
For the payload, we strategically designed basic OS commands that would grant us valuable information about the targeted system, including its public IP address, username, hostname, and current path. These details would provide essential reconnaissance data to assess the target’s security posture.
To execute our payload seamlessly after the package is installed on the targeted system by the company’s developers, we took advantage of NPM’s convenient feature known as “postinstall”. By specifying a script in the package.json file under “postinstall,” we ensured that our payload would automatically trigger after the package installation process was completed.
One crucial element we considered during the PoC development was the need for the internal package to be fetched from the public NPM registry. To achieve this, we published our custom package with version 99.99.99 on the NPM website. This approach ensures that the client application would fetch our “malicious” version hosted on the NPM website since it seeks the latest version of the internal package (“internal_dependency”), as shown in the above image (No. 2).

After waiting a while, we observed a couple of HTTP POST requests containing our crafted payload sent to our controlled web server – one from a Linux machine and the other from a Windows machine. These requests proved that the targeted machines had successfully installed our hosted package and triggered the execution of the system commands we controlled.


Mitigation
If you have encountered any of the above scenarios, please follow to instructions below provided by Clear Gate for immediate mitigation and to prevent Dependency Confusion attacks further
- Explicitly Specify Package Sources: Clearly define and prioritize the sources from which your package manager should fetch dependencies. This ensures that internal packages are fetched from private registries before searching public repositories.
- Use Package Locking: Utilize package-lock.json (for NPM), Pipfile.lock (for Pip) to lock dependency versions. This ensures that your application always uses the intended versions, preventing potential substitutions.
- Audit and Monitor Dependencies: Regularly audit the dependencies in your projects to identify vulnerabilities and update them to secure versions. Use automated tools to track and notify you of any potential security risks in your dependencies.
- Implement Access Controls: Enforce strict access controls to limit who can publish and update packages in your internal package registry. Authenticate and authorize users based on their roles and responsibilities.
- Verify Package Authenticity: Verify the authenticity and integrity of packages by using cryptographic signatures or checksums before installation.
Conclusion
In conclusion, exploring the Dependency Confusion attack and its attack vectors, such as Remote Code Execution (RCE), highlights the critical importance of securing software development processes. The real-life scenario encountered during our penetration test illustrates the risks of exposing sensitive configuration files, such as package.json.
Organizations should prioritize cyber security risk assessments and penetration tests to mitigate risks in dependencies deployments, which have become increasingly popular among companies developing SaaS products. Clear Gate, a trusted cybersecurity provider, offers in-depth manual penetration tests to help organizations strengthen their development process security and protect valuable data from potential threats.