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 now 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 can be faster. It’s now more about welding existing pieces together, rather than building them yourself. Open source libraries solve fundamental engineering problems, allowing engineers to focus their time on more complex tasks.
- Tools like package managers make it easy to manage and add third-party dependencies. Every programming language or IDE comes with an integrated package manager support.
- Over time, the way APIs are exported and used becomes clearer and simpler. Open source maintainers offer clear APIs, simple documentation, and code samples.
Every new technology has its risks, though, and attackers can exploit weak points in software that uses open source. An attacker can gain information about open source libraries used by an application, and in other cases, can simply maintain an arsenal of exploits for popular open source packages and attempt to use these until one succeeds. In the case of open source packages, attackers have full access to:
- Its code, which they can scan for zero-day vulnerabilities.
- Issues and security tickets that are managed on GitHub, GitLab, etc., which can help find vulnerable areas for exploitation.
- Current and past vulnerabilities, which can be very helpful when the library in use is not up to date. These vulnerabilities have detailed descriptions and 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, a software composition analysis (SCA) tool such as Checkmarx CxSCA detects your third-party libraries and versions in use and informs you of existing vulnerabilities. It’s important to recognize that not all libraries in a project may apply since some may not be in use.
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 third-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 is 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 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, the processing of which 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. 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 third-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 irrelevant.
- They may be considered 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 actually much lower than assumed, and that’s good news for developers. Fewer vulnerabilities means 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 organization 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.