If you look at the way code is written today vs. a few years back, one of the major changes is the transition to open source. What was once considered an unsafe methodology has grown and matured, and nowadays almost every software project uses open source libraries. Today, software engineers prefer to use existing open source code, instead of writing everything themselves.
The benefits are significant:
- Code development becomes even faster. It’s now more about welding existing pieces together, rather than building those pieces yourself. Today, open source libraries solve fundamental engineering problems, allowing engineers to focus their time on more complex tasks.
- Tools like package managers make it simple to manage and add 3rd party dependencies. Every programming language or IDE comes with an integrated package manager support.
- Overtime, the way APIs are exported and used becomes clearer and simpler. Open source maintainers offer clear APIs, simple documentation, and code samples.
But every new technology has its risks, and attackers can exploit weak points in a software that uses open source. An attacker can gain information about open source libraries used by an application, and in other cases, an attacker can simply maintain an arsenal of exploitations for popular open source packages and attempt to use those attacks until one succeeds. For open source packages, attackers have full access to:
- Its code, that they can scan for 0-day vulnerabilities
- Issues and security tickets, that are managed on GitHub, GitLab, etc. These issues can help find vulnerable areas for exploitation
- Current and past vulnerabilities, that can be very helpful when the library in use is not up to date. Those vulnerabilities have detailed descriptions, advisories, and even the patches themselves are open source. An attacker can utilize those vulnerabilities and attempt to attack the application, and if the library uses an old version, the attack will succeed.
To manage such risks, you have SCA (Software Composition Analysis) tools, such as Checkmarx’s CxSCA, that detect your 3rd party libraries and versions in use and informs you of existing vulnerabilities. It is important to recognize that not all libraries in a project may apply since some may not be utilized.
Tracking existing vulnerabilities is important, but it’s not enough. The average project has dependencies, that in turn have their own dependencies. Overall, there can be hundreds or thousands of libraries with hundreds of vulnerabilities in your project.
Nowadays, solving those vulnerabilities can take lots of time, while developers need to put efforts into developing new features as well. Managing security vulnerabilities of 3rd party packages is often not a one-time thing, but rather an on-going process, so it’s important for an SCA tool to prioritize the risks. This way, developers know what the most crucial risks to solve are.
But how do you prioritize a vulnerability?
The popular method is to prioritize vulnerabilities by the CVSS—a score given to a vulnerability based on the impact, how easy it is to exploit, etc. Every vulnerability that was made public has this score. However, this methodology is too simplistic, since exploitability is the most crucial aspect.
Exploitability of a Vulnerability
Let’s assume that a vulnerability is triggered by a foo() method in a library that you’re using. If your code doesn’t call foo() in any flow, either directly or indirectly, the vulnerability is in fact not exploitable. If so, the priority of fixing it is low and efforts should be redirected to exploitable vulnerabilities instead.
Looking at it from an attacker’s perspective, for a vulnerability to be exploitable:
- The method foo() needs to be called. This can require a carefully crafted input, whose processing will trigger a call for foo().
- The attacker needs to control the data flow for foo(). Usually, calling a method with “regular input” won’t trigger any unwanted behavior. The unwanted behavior is triggered when a carefully crafted input from the attacker reaches foo(). Meaning, the vulnerable method needs to be callable and its input controlled.
Developers today can use an entire library for a single API method out of dozens of APIs. Also, libraries they use have their own 3rd party libraries, with only a partial use of available APIs. This means that given a vulnerability in one of your dependencies, the probability of exploiting it can be below 5%. This has serious implications:
- Current prioritizations of vulnerabilities are defocusing. Instead of fixing exploitable vulnerabilities first, efforts are put into risks that may be sometimes irrelevant.
- They may be considered as False Positives. You would assume that a critical risk is a top priority, but if the relevant code flow can’t be reached, there’s nothing critical here.
- The true number of vulnerabilities that need to be addressed is in fact much lower than assumed today, and that’s good news for developers. Fewer vulnerabilities mean far less effort to remediate them.
By using CxSAST to statically analyze the project’s source code and the source code of all its used packages, when examining the call graphs and data flows, the exploitability and risk can be evaluated.
With CxSCA, Checkmarx enables your organizations to address open source vulnerabilities earlier in the SDLC and cut down on manual processes by reducing false positives and background noise, so you can deliver secure software faster and at scale. For a free demonstration of CxSCA, please contact us here.
In the next blog post, we’ll dig deeper into the research behind Exploitable Paths, sharing challenges and insights we collected along the way.