Researchers at Aqua Nautilus found that 8.2% percent of the most downloaded npm packages are officially deprecated, but due to inconsistent practices in handling package dependencies, the real number is much larger, closer to 21.2%. Moreover, some package maintainers, when confronted with security flaws, deprecate their packages instead of reporting them, getting a CVE assigned or remediating the vulnerabilities. These gaps can leave developers unaware that they are using unmaintained, vulnerable packages, and create opportunities for attackers to take over unmaintained code that continues to be used.
In this blog we will explain about the deceptive deprecation gap, introduce a new open source tool to scan your packages for deprecated dependencies, and explain what Aqua customers can do to mitigate these risks.
How this research began
Initially, our research focused on identifying vulnerabilities on a large scale through the use of Static Application Security Testing (SAST). To uncover these security flaws systematically, we employed Semgrep—a powerful SAST tool that utilizes a combination of rules and conditions to search for patterns inside your code.
At the start of the research, we initially targeted “low-hanging fruit” vulnerabilities to validate our hypothesis. To this end, we used the default rules of the Semgrep community, searching for Prototype Pollution, XSS, SQLI, Command injection, etc.
During our research, we identified several vulnerabilities. Notably, CVE-2023-26364 was effectively addressed by Adobe’s security team. However, many other vulnerabilities reported by us were unaddressed because of unresponsive maintainers.
Among the vulnerabilities uncovered, a few stood out. After we reported the vulnerabilities, the maintainers decided to archive the repositories rather than fix the issues.
This made us wonder about the security status of other deprecated packages and archived repositories. Might they harbor unresolved vulnerabilities that have not been assigned a CVE? Absent a CVE, security scanners would fail to notify users about the risks associated with these packages, potentially leaving them exposed.
A prime example of this issue is the
sntp package, which has been deprecated. Below is the deprecation message provided by the maintainers:
You can see that they clearly state that this package is no longer maintained, which could lead to critical security vulnerabilities, and you should switch to another package. However, as mentioned earlier in the blog, not every maintainer demonstrates this level of responsibility to their users.
Thinking about the risks of being dependent on a deprecated package made us realize: any package that depends on a deprecated package may, unknowingly, become vulnerable itself.
It’s crucial to acknowledge that the presence of a vulnerability in a dependency does not necessarily compromise the dependent package. This risk depends on whether the affected code is actually executed by the dependent package. Nevertheless, without detailed vulnerability data, the safest course of action is to always update to the latest version or replace a deprecated package with an alternative.
What is a deprecated package
Understanding the inherent risks associated with the use of deprecated packages leads us to one fundamental question: What exactly constitutes a deprecated package?
The initial thought about deprecated package is to check if it is deprecated at the npm registry, for example the package request:
Nonetheless, as demonstrated in our prior examples, there are instances where maintainers choose to archive a package’s repository in GitHub rather than deprecate it officially on npm. Such actions prompt us to look for other criteria to determine a package’s deprecation status:
- If the repository linked to a npm package is inaccessible, should we then regard the package as deprecated? Is the repository no longer available because it has been deleted (indicative of deprecation), or has it simply been made private?
- In cases where a package does not have an associated repository, what measures can we use to ascertain its maintenance status?
There is no absolute answer to these questions. It’s essential for each organization that utilizes npm packages to establish its own set of criteria for determining the deprecation status of a package, although common sense dictates that “orphaned” npm packages should be treated with caution. While there are various other criteria that can be employed to ascertain whether a package is deprecated or not, including factors such as the last publish date and the last commit date, in this blog, we focused on what we believe should be the primary criteria of deprecation.
Dependency Analysis of Top npm Packages
In npm, packages can form a complex graph of dependencies, so it’s critical to assess not just their direct dependencies, but also their transitive ones—that is, the dependencies of dependencies. This chain can extend several layers deep, potentially magnifying the impact of a single deprecated package.
We wanted to check from the top 50K downloaded npm packages, how many are, directly or indirectly, reliant on deprecated packages.
For this statistical analysis, we searched for packages that are explicitly deprecated or have direct deprecated dependencies. We chose this approach because even though a deep, vulnerable package might exist, if the top-level package does not execute the vulnerable code, it may not pose an immediate threat. However, it’s crucial to acknowledge that deprecation in a deep dependency can still have severe consequences.
Here you can view the results of deprecation of the top npm packages:
As reflected in the chart above, according to the official “deprecation” definitions 8.2% of the top 50K packages are considered deprecated, as opposed to up to 21% of the packages according to our extended definitions.
As previously mentioned, defining package deprecation lacks a standardized criterion. Consequently, the composition breakdown of the chart varies based on your deprecation criteria:
- If you strictly adhere to npm’s deprecation status, approximately 8.2% of the packages fall into the deprecated category.
- Considering archived repositories as deprecated as well increases the deprecation rate to 12.8%.
- For those concerned about package maintenance and repository not being deleted, adding the criteria of GitHub unavailability results in a deprecation rate of 15%.
- Lastly, if you seek packages that are actively maintained with a visible repository, commit history, and issue tracking the inclusion of the ‘no repository linked’ criterion raises the deprecation rate to 21%.
The number of weekly downloads for the deprecated packages from the top 50k packages, according to our extended definitions, amounts to 2.1 Billion Downloads!
It’s generally advisable to utilize only fully maintained packages, where the maintainers actively address security issues and provide ongoing support for the package. Using unmaintained packages increases the risk of unfixed vulnerabilities and even threat actors taking over packages to insert malicious code. Hence, it’s recommended to incorporate all the criteria presented in this blog.
It’s important to note that we chose to analyze the top npm packages because they are the most depended-upon packages, which means that all the dependent packages that rely upon them can be marked as deprecated as well, suggesting an even broader problem.
Examples of such depended upon packages are
- through– github archived but has more than 3000 packages as its direct dependents.
- request – package is deprecated, but it has 55,000 packages as its direct dependents.
Aqua Nautilus Dependency Deprecation Checker
Now that we understand how risky relying on a deprecated package can be for an organization, how can organizations check if they are relying, directly or indirectly, on a deprecated package?
If we could provide insight to organizations about hidden threats and dependencies among their deprecated software artifacts, they’d be able to replace certain packages that are considered deprecated to “healthier” packages.
To that end, we’re introducing a new open-source tool called “Dependency Deprecation Checker”. This tool, which can be found on GitHub, scans your package.json file and checks for dependencies that rely on deprecated packages.
The tool lets you choose the criteria for what is considered a deprecated package in your organization, so it is customizable to your needs.
The tool is currently a Proof of Concept (PoC) and doesn’t provide a comprehensive coverage of deprecated packages, but it still yields insightful results.
Below is the outcome of executing the Dependency Deprecation Checker using the sample package.json file provided in the repository:
We can observe that it prints a list of our direct dependencies which are deprecated, highlighting the chain of deprecation. This makes it easier to pinpoint the root cause of deprecation.
Summary and Mitigations
Our research reveals a significant concern within the npm ecosystem: a substantial portion of the most utilized npm packages are deprecated, posing risks to the stability and security of many projects.
This situation becomes critical when maintainers, instead of addressing security flaws with patches or CVE assignments, opt to deprecate affected packages. What makes this particularly concerning is that, at times, these maintainers do not officially mark the package as deprecated on npm, leaving a security gap for users who may remain unaware of potential threats.
This also raises the Open Source Maintenance debate, should open source maintainers be obligated to address vulnerabilities in open source projects they contribute to during their free time? There is a well-known example of a maintainer who became frustrated with the community’s demands to maintain his package, leading him to insert malicious code, you can read more about it here.
To address these concerns and bolster the security posture of organizations using npm packages, we recommend the following steps:
- Establish Deprecation Protocols: Organizations should define what constitutes a deprecated package beyond the npm registry’s designation. This could include criteria such as the inaccessibility of repositories or the lack of recent maintenance activity.
- Adopt the Dependency Deprecation Checker: Our newly developed tool, the “Dependency Deprecation Checker”, available on GitHub, provides organizations with the means to scan their package.json files for deprecated package dependencies.
- Update or Replace Deprecated Dependencies: Organizations should prioritize updating to more actively maintained packages when deprecation is detected.
By implementing these measures, organizations can significantly reduce the vulnerabilities associated with deprecated npm packages and maintain the integrity and security of their applications.
What Aqua customers should do:
Aqua customers can benefit from our Software Supply Chain Security (SSCS) solution to instill practices that prevent the use of deprecated npm packages in their builds, as part of a holistic approach to supply chain security and governance.
Mitigations in Aqua SSCS include:
- Conduct regular scans of your code dependencies to evaluate their security posture, including the identification of any deprecated dependencies.
- Monitor your code dependencies for behavioral changes such as using unpinned dependency version that suddenly published after long time.
- Establish preventive measures using assurance policies that prevent the integration of high-risk dependencies into your codebase and cloud environment.