Project Safe Source: Identifying potential vulnerabilities in Wolfi upstream
TL;DR
A security scan with CodeQL of over 1,000 open source projects packaged in Wolfi found seven classes of potential vulnerabilities across 226 projects — 1,878 alerts in total — that can potentially be fixed with automated (or “bulk”) pull requests. This experiment, part of a nascent initiative from Chainguard Labs called “Project Safe Source,” represents another step toward making Chainguard the safe source for open source.
Introduction
Chainguard’s mission is to be the safe source for open source. It is an awesome mission. It is also a challenging mission given the many meanings of “safe” when it refers to all code on the internet. Chainguard Images, Chainguard’s flagship product, exemplifies many of these meanings: few or no CVEs, fast CVE remediation, a radical minimalism approach, frequent updates, and transparency, among others. But there are other definitions of “safe” open source too.
One potential definition of safe open source is the use of open source components that have been proactively vetted for vulnerabilities, unknown security flaws (or “zero days” in security researcher-speak) that could be exploited by a wily attacker. To that end, the security research presented here, the first of more experiments to come, aimed to identify security vulnerabilities that commonly exist in Wolfi’s upstream dependencies (“Wolfi upstream”) and that would be good candidates for bulk pull requests, or automated proposed fixes generated by a bot and sent to the open source projects. This project therefore used the CodeQL static analysis tool to scan over 1,000 open source projects currently packaged in Wolfi and then identified promising candidates for automated fixes via bulk pull requests.
This scan found seven classes of potential vulnerabilities across 226 projects — 1,878 potential vulnerabilities in total — that can potentially be fixed with automated (or “bulk”) pull requests. What does it mean? Proactively finding and fixing vulnerabilities at scale in Wolfi upstream looks feasible, really feasible. Keep reading to find out more.
Why use bulk pull request generation to make open source safer?
Bulk pull request generation addresses one of the key problems in securing open source software: scale. There is just so much open source code — millions and millions and millions of projects out there — code that you are likely relying on to read this article, code that runs your car, flies aircraft, and propels vehicles in outer space. Unfortunately, within that open source code, there are inevitably vulnerabilities just waiting to be found by attackers. Nobody writes bug-free code.
Consequently, countless human hours are spent every year finding common security vulnerabilities with relatively simple fixes. These vulnerabilities aren't sexy, cool, or new; they’ve been known for years, but they're everywhere. One might think that simply detecting these security vulnerabilities and reporting them would be useful, but in the real world open source software maintainers, often volunteers, can feel overwhelmed by a deluge of bug reports. That’s why a project that creates fixes — not just finds bugs — represents a worthwhile approach to making open source safer.
In fact, my past security research has generated north of 6,000 automated pull requests to fix widespread security vulnerabilities across open source software. This first experiment of Project Safe Source therefore sought to assess whether there are common vulnerabilities in Wolfi upstream that could be appropriate for bulk pull request campaigns, efforts that would proactively find and fix vulnerabilities before an attacker takes advantage of users of this software.
How we identified candidate vulnerabilities for bulk pull requests in Wolfi upstream
I first forked the upstream GitHub repository associated with 1,403 Wolfi packages and then ran CodeQL, a static application security testing (SAST) tool, on as many of the repositories as possible. These tools scan source code and use complex search patterns to attempt to detect common security vulnerabilities. CodeQL is particularly useful because it is free and because it uses “variant analysis,” which allows a security researcher to write custom CodeQL queries and run them against thousands of open source projects at a time to find new security vulnerabilities. After running CodeQL successfully on 1,368 projects, I had a pile of alerts: 10,165 alerts across 1,262 projects. See table 1 below for a summary of alerts by programming language and severity.
Table 1.
Note: These findings exclude those associated with test suites.
Unfortunately, a downside of tools like CodeQL is that many alerts are false positives. This can leave a lone security researcher digging through vulnerability alerts looking for a needle in a haystack. While the haystack is smaller than the monumental amount of raw code out there, it’s still a haystack.
So I went digging! I specifically looked for vulnerabilities that are “good” candidates for automated fixes. Vulnerabilities that either:
have a vulnerable method call with a one-to-one replacement with a non-vulnerable method call,
simply require adding method calls that perform additional validation to a document parser,
insert guard logic to validate a value before it is used again,
or, involve simple replacements, insertions or deletions that could be done with regular expressions.
What candidate vulnerabilities did I identify for bulk pull requests in Wolfi upstream?
I present the candidates for bulk pull requests by their programming language ecosystem.
C/C++
Multiplication result converted to larger type
GitHub ID: cpp/integer-multiplication-cast-to-long
Wolfi Repositories Impacted: 70
Alert Count: 873
After filtering out test results, this was the most common CodeQL security finding in Wolfi Upstream, totaling 873 alerts. Additionally, CodeQL flags this alert as “high” severity. This vulnerability flags when two integers are multiplied together and assigned to a long value.
int i = 2000000000;
long j = i * i;
The above code will result in j being -1,651,507,200 instead of 4,000,000,000,000,000,000. The fix is straightforward: cast the values to long types before multiplying.
long j = (long) i * i;
Integer overflow vulnerabilities in C/C++ code can have a massive impact. For example, in the case of CVE-2022–36934, an integer overflow in WhatsApp led to remote code execution in an established video call.
Go
Incorrect conversion between integer types
GitHub ID: go/incorrect-integer-conversion
Wolfi Repositories Impacted: 111
Alert Count: 836
After filtering out test results, this was the second most common CodeQL security finding in Wolfi Upstream. This particular alert flags the use of int32 to convert a value that is not an int32 into an int32. This can cause an integer overflow, which can lead to unexpected behavior. In go codebases, this has often been observed to cause denial of service style vulnerabilities.
This sort of simple coding problem is usually relatively easy to fix with automated refactoring and could make a good candidate for automated bulk pull request generation. Unfortunately, OpenRewrite, a tool I traditionally use for generating automated fixes, currently doesn’t support Go. There are, however, other abstract syntax trees (AST) manipulation libraries for Go do exist. In short, this could be a good candidate.
Javascript/HTML
Inclusion of functionality from an untrusted source
GitHub ID: js/functionality-from-untrusted-source
Wolfi Repositories Impacted: 14
Alert Count: 33
There are many projects that ship HTML that loads Javascript from content delivery networks like Cloudflare. However, these sometimes don’t use integrity checks to verify that the Javascript they are being served has been maliciously manipulated. Attacks like this are how exploitation like Mage Carting occurs. This could be easily improved by generating the integrity SHA-256 checksum for the resource and adding it to the HTML.
Ruby
Use of Kernel.open or IO.read or similar sinks with a non-constant value
GitHub ID: rb/non-constant-kernel-open
Wolfi Repositories Impacted: 16
Alert Count: 84
If Kernel.open is given a file name that starts with a | character, it will execute the remaining string as a shell command. If a malicious user can control the file name, they can execute arbitrary code. The same vulnerability applies to IO.read, IO.write, IO.binread, IO.binwrite, IO.foreach, IO.readline and URI.open. This vulnerability has appeared in a few popular Ruby projects including Nokogiri (CVE-2019-5477).
This vulnerability fix is basically a 1:1 replacement with a different API call, so it would be a good candidate for a “quick fix.”
Java
Resolving XML external entity in user-controlled data
GitHub ID: java/xxe
Wolfi Repositories Impacted: 3
Alert Count: 17
In 2017, External Entity Processing (XXE) was fourth on the list of the OWSAP top 10 application security risks. Parsing XML has long been a source of security vulnerabilities in the Java ecosystem; according to GitHub’s advisory database, of the 301 CVE’s with “XXE” in the description, 218 (72%) impacted projects from the Java ecosystem.
Java ships with nine different XML parsers, each with their own API or use case. By default, all of the Java parsers built into the Java standard library have some sort of functionality that must be disabled in order to adequately ensure that they are “safe” to parse untrusted user input. Semgrep has an excellent resource they’ve published on how to adequately protect the particular XML parser being used.
Ideally, the XML parsers themselves would be secure by default, and this additional functionality would be opt-in, not opt-out, like it is today. This vulnerability is therefore a good candidate.
Zip slip
GitHub ID: java/zipslip
Wolfi Repositories Impacted: 5
Alert Count: 11
Zip slip is a path traversal vulnerability in the logic used to unpack zip archive files. Zip archive files are a key value map of file name to compressed file contents. If an attacker crafts a malicious zip archive containing a path traversal payload, and a zip archive unpack logic does not adequately guard against these payloads, the attacker can write files to arbitrary locations on the file system. This can lead to remote code exclusion. The fix for this vulnerability is to add logic that guards against path traversal within the unzip logic.
In 2018, the Synk research team revealed that the zip slip vulnerability had impacted the OSS code for projects from organizations like Oracle, Amazon, Spring/Pivotal, Linkedin, Twitter, Alibaba, Jenkinsci, Eclipse, OWASP, SonarQube, OpenTable, Arduino, ElasticSearch, Selenium, JetBrains and Google.
Python
Insecure Temporary File
GitHub ID: py/insecure-temporary-file
Wolfi Repositories Impacted: 7
Alert Count: 24
Functions that create temporary file names (such as tempfile.mktemp and os.tempnam) are fundamentally insecure because they do not ensure exclusive access to a file with the temporary name they return. The file name returned by these functions is guaranteed to be unique on creation but the file must be opened in a separate operation. There is no guarantee that the creation and open operations will happen atomically. This provides an opportunity for an attacker to interfere with the file before it is opened. The fix for this is a rather straightforward replacement with the new NamedTemporaryFile API.
What’s next?
Due to the sheer number of potential vulnerabilities identified, it would be nearly impossible for any single security researcher to triage every alert and report every vulnerability identified. Many of these alerts are likely unexploitable. However, fixing them through automated pull request generation could have one of two positive impacts: (1) Actually fixing a valid security vulnerability or (2) adding additional security hardening that would not impact performance. Of course, open source project maintainers could also add static analysis tools like CodeQL to their project in order to detect and fix vulnerabilities like this.
We’ll be exploring ways to put these candidates for bulk pull request generation into action. Additionally, during the course of this research, I discovered vulnerabilities in two components of Wolfi’s upstream that were severe enough to warrant being reported to the maintainer. We’ll be discussing this research in a later blog post, so be on the lookout. Until next time!
About the Author
Jonathan Leitschuh is a Principal Software Security Researcher at Chainguard. Previously at the Open Source Security Foundation (OpenSSF) project Alpha-Omega. Jonathan was the inaugural Dan Kaminsky Fellow @ Human Security. He’s best known for the July 2019 Zoom 0-day vulnerability disclosure.
Ready to Lock Down Your Supply Chain?
Talk to our customer obsessed, community-driven team.