Open source software libraries have become an integral part of modern software development. They are widely used by developers to accelerate the development process and reduce costs. On average, open source libraries make up 70-90% of an entire software application. However, the use of open source libraries also comes with hidden security risks that could potentially harm your organization's reputation and financial well-being.
In this article, you’ll learn about the hidden security risks of open source software libraries and ways to mitigate them.This is not meant to be an exhaustive list, but covers the most important tactics for vulnerability management.
Hidden security risks of open source software libraries
Understanding the sources of security risks for open source software libraries is crucial for developers and security professionals alike, as it enables them to proactively identify and address potential security vulnerabilities, ultimately enhancing the overall security posture of their software systems. In this section, you’ll explore four key sources of these hidden security risks:
- Vulnerabilities in libraries
- Lack of control over the source code in open source libraries
- Considering and mitigating vulnerabilities in a complex dependency tree
- The use of outdated libraries
Vulnerabilities in libraries
Using open source libraries carries a significant risk due to the potential presence of exploitable vulnerabilities. These vulnerabilities can arise from programming mistakes or design shortcomings in the library's code.
However, it's crucial to understand how to detect packages and assess their vulnerability. Let's explore a few examples. New Relic has consistently provided visibility into the libraries utilized by your code. Within the Environment section of your application or service, you gain access to a comprehensive overview of all packages and their respective versions.
New Relic Vulnerability Management adds an automatic check against the GitHub Advisory Database for common vulnerabilities and exposures (CVE). This means that latest releases of the New Relic APM agents automatically detect CVE data in the libraries used by your service.
Take a moment to examine the next screenshot, which displays the complete list of libraries employed by your application. This includes libraries that may or may not have known Common Vulnerabilities and Exposures (CVEs) for the specific version you are utilizing.
In this example, the application incorporates the vm2 library, specifically version 3.9.11, which is associated with a total of 5 recognized vulnerabilities. New Relic acquires this data by cross-referencing the package's name and version against the GitHub Advisory Database. Subsequently, this information is then relayed to New Relic Vulnerability Management, where it can be accessed for examination and analysis.
By selecting the library's name, you can access detailed information pertaining to each of the identified vulnerabilities. This includes relevant details such as the availability of a fix for each vulnerability.
Lack of control over open source code
When using open source libraries, developers often have limited control over the code they are using. This can make it difficult to detect and fix security issues.
One of the biggest benefits of using open source libraries is not having to reinvent the wheel. When someone has already developed code that solves a certain problem, it is often more efficient to leverage the existing functionality. But let's explore a scenario where this lack of control can lead to a negative consequence.
Almost every programming language provides a package manager to facilitate the development process. For instance, Node.js employs NPM, Java has Maven/Gradle, and .NET uses NuGet. Now imagine that you are searching for a library in NPM that solves your requirement to add color coding to console output. You head over to https://npmjs.com and search for suitable packages:
You start investigating the first package in the list called “colors”. The information looks promising, the screenshot indicates that this is exactly what you need, and the fact that this package receives roughly 20 million downloads a week also gives you confidence that colors is indeed useful and maintained.
The installation is as simple as running npm install colors and you are good to go to use it in your code by importing it via var colors = require('colors');.
However, it's unlikely that the majority of users actually visit GitHub at https://github.com/Marak/colors.js to review the code, even at a high level. Most developers tend to rely on the assurance that open source software is generally safe to use.
Once this package is incorporated into your code and confirmed to deliver its intended functionality, you likely release your software and move on. And monitoring subsequent changes made to the library's code may not be a top priority for you.
Well, that is until you come across surprising news like the article published by Bleeping Computer, an information security and technology news publication.
This article describes how the creator of these libraries deliberately incorporated an infinite loop, causing severe damage to countless projects relying on 'colors' and 'faker.' The developer also added some information to the standard output of the colors library with the text “LIBERTY LIBERTY LIBERTY”. It turned out that he was sick and tired of working “for free” on these libraries and used this breach as a statement to the open source community.
Dependencies
Open source libraries often have dependencies on other libraries, which can create a complex web of code that can be difficult to manage. This can make it challenging to keep track of security issues and vulnerabilities.
Let’s look at an example. Another popular open source library is mongoose, which is an object modeling tool for MongoDB. NPM provides information about the dependencies of this package.
As you can see, mongoose itself is dependent upon a number of other packages such as bson, kareem, mongodb, mpath, mquery, ms, and sift. In order to check quality and potential vulnerabilities of mongoose, you would also need to check all of mongoose’s dependencies, and then also the dependencies of mongoose’s dependencies. You can end up with an entire dependency tree that would require a lot of effort to manage.
Outdated libraries
Many open source libraries are not regularly updated, which can leave them vulnerable to attack. This can be especially problematic when vulnerabilities are discovered in older versions of a library that are still in use.
In the previous example of the vm2 library, you saw that version 3.9.11 comes with a total of five vulnerabilities. Four of them are marked as critical and one with medium severity.
Often developers lock libraries at a specific version in order to make sure that a newer version of the library does not break their application.
This is of course a reasonable practice. But it also comes with high risk for the organization. Especially if the exploit maturity indicates that there is public knowledge about a proof-of-concept or detailed explanation of how to exploit this vulnerability.
Five ways to mitigate these open source security risks
Now that you are familiar with these risks, it is crucial to explore effective strategies for mitigating them. This section delves into five essential practices that can help safeguard your software projects against potential vulnerabilities:
- Conducting regular security audits allows for thorough vulnerability assessment.
- Staying up-to-date with library versions ensures access to the latest security patches.
- Choosing reputable libraries guarantees reliable and trustworthy code.
- Monitoring dependencies helps prevent security breaches.
- Lastly, conducting code reviews by experienced developers adds an extra layer of protection. Let’s dive into each of these in more detail.
Conduct regular security audits
Conducting regular security audits can help identify vulnerabilities in open source libraries. This can include using vulnerability scanners and penetration testing to identify potential weaknesses in the code.
Ideally, this task is fully automated and integrated into the software development lifecycle, all the way from development to testing and deploying your applications. You may even want to run these scans continuously while a release of your software is running in production. This is especially important for zero-day vulnerabilities—a vulnerability in a library that has been disclosed but is not yet patched.
Stay up-to-date
It's important to stay up-to-date with the latest security patches and updates for open source libraries. This can help address any known vulnerabilities and reduce the risk of a security breach.
As with security audits, this task can and should be automated so that you can make sure to always leverage the latest release of a library. The job of making sure that upgrading a library does not break your build can and should be covered by automated tests, ideally on a unit-level. This way, you can get immediate feedback that a newer version of a library (major or minor) may not be fully compatible with the current version that you used up until this point.
It’s important to acknowledge that staying up-to-date does not necessarily mean always upgrading to the latest version. Ensure that staying current is a consistent priority, and learn and validate what the latest versions bring to the table. If you can upgrade, fine. But as mentioned earlier, there may be perfectly valid reasons to lock your code and keep a specific version. These reasons and decisions should probably be documented so that the potential risk attached is known to all stakeholders.
Use reputable libraries
When selecting open source libraries, it's important to use reputable and well-established libraries that have a track record of being secure and reliable. This can reduce the risk of using libraries that may have vulnerabilities.
You can check libraries in many ways. A good starting point is probably the package manager you are using in your application. In the case of Node.js, it is probably NPM. For example, if you want to check the mongoose library and look at some data points, you can head over to https://www.npmjs.com/package/mongoose.
You can see that it is regularly maintained (8 days ago), it is quite popular (many downloads) and seems to have active contributions (pull requests). As a next step, you could then check public vulnerability databases such as the NIST National Vulnerability Database (NVD).
Alternatively, GitHub Advisories is also a great source of information.
Just like you saw earlier with the colors library, even if you use a popular library that seems reputable, you can still run into serious problems. But if you incorporate automated tests, any issues should be identified much earlier in the development lifecycle and not only when running the application in production. Also, the observability metrics generated when testing and comparing the newer releases of your software against your previous releases should indicate an anomalous behavior in parts of the application where the colors library kicked in with the infinite loop.
Monitor dependencies
It's important to monitor the dependencies of open source libraries and ensure that they are up-to-date and secure. This can help reduce the risk of vulnerabilities in the dependencies that could be exploited by attackers.
You saw examples of monitoring vulnerabilities in libraries and dependencies of libraries earlier in this blog. In each step of your software development lifecycle you should proactively monitor your libraries and their dependencies in an automated manner and get alerted as soon as issues are identified. New Relic APM agents provide automatic CVE detection in your project’s libraries, as well as a breadth of third-party integrations (such as AWS Security Hub, Dependabot, or Snyk) and a security API that you can use to import and monitor dependencies and their vulnerabilities.
Implement code reviews
Implementing code reviews can help identify security issues in open source libraries as well. This can involve reviewing the code for potential vulnerabilities, obvious issues, or inconspicuous issues that someone with more experience can spot.
All the practices you learned above are important to get baseline security processes in place. But this should not stop you from having regular code reviews with peers. Machines and automated processes are a great way to start having basic and repeatable checks in place—but nothing can beat the good sense of intuition from a human.
You can read the full blog post at New Relic here.