This blog post is the first in a series about hardening the security of the Exiv2 project. Most of the steps that I’m taking with Exiv2 are generally applicable to other projects, so my goal is to share some tips that will hopefully help you harden the security of your own project. Sometimes, the easiest way to learn is by example. For example, I found it much easier to get started with libFuzzer by copying the setup from another project than by reading the documentation. So, I’m sharing examples from Exiv2 that I hope will help you, too.
There will be four posts in this series:
- Creating a security advisory process
- Kev’s three rules of bug fixing
- Adding custom CodeQL queries to code scanning
- Adding a libFuzzer target and enrolling Exiv2 in OSS-Fuzz
Exiv2 is a command-line utility and C++ library for reading or modifying the metadata of image files. Last year, I wrote a blog post about how I became a contributor on the Exiv2 project and described how I used AFL to search for bugs in Exiv2. In the conclusion, I confidently predicted that fuzzing was unlikely to find many more bugs in Exiv2. My prediction held up well for almost a year, but recently more bugs have started coming out of the woodwork. The first of the new batch was #1522 reported on April 5, 2021.
What changed? It seems that several people have recently taken an interest in fuzzing Exiv2 and have started testing Exiv2’s many command line options. When I fuzzed Exiv2 last year, I only tested Exiv2 in its default configuration—without any extra command line options. Of the 20 new issues that have been found recently, only four affect Exiv2 in its default configuration: an out-of-bounds read found by @yuawn, an uninitialized variable also found by @yuawn, an infinite loop found by me, and an out-of-bounds read found by me. The others require extra command line options. I think very few people are downloading untrusted images off the internet and running Exiv2 on them with extra options, so I consider the security risk of such bugs to be extremely minor. But it’s much easier to fix the bugs than argue about how important they are, so I welcome the bug reports.
One of the reasons I like contributing to Exiv2 is because it allows me to see security from the other side. My main job as a member of GitHub Security Lab is to find and report vulnerabilities in open source projects. I’m typically on the offensive side, or “red team,” but for Exiv2 I’m on the defensive side—the “blue team.” There’s no glory on the blue team, just a seemingly endless stream of low severity bugs that need to be fixed. I hope that my blue team experience helps to give me more empathy when I am reporting bugs to other projects.
When the new batch of vulnerabilities started rolling in, it happened the same way as it has in the past, with public issues like this one. Right now, there isn’t a great way for open source repositories to accept security disclosures privately, but I’ll explain how we use our security policy and GitHub’s security advisories for Exiv2. A security advisory is similar to a confidential issue, except it can only be opened by a project administrator.
Step one of creating a security advisory process is to add a security policy. The recommended way to do that on GitHub is by adding a file named
SECURITY.md. The policy is displayed in the security tab of the project:
Notice that the security tab also shows the security advisories that have been published for the project. More on that later.
You can read Exiv2’s security policy here. I opted for the low-tech solution of offering my own email address as the security contact address. A fancier solution would have been to create an official email address like firstname.lastname@example.org, but I wanted to get it done quickly and couldn’t be bothered with the distraction of creating a new mailing list.1 My intention is to keep the email conversation as brief as possible. When I receive an email about a vulnerability in Exiv2, I create a draft security advisory and invite the person who reported the issue to be a collaborator on the advisory. All subsequent communication can take place in the comments section of the advisory.
We have tried to emphasize a couple of important points in the security policy:
- Reproduction steps. There’s nothing worse than receiving an unclear bug report, so the policy contains detailed instructions on what’s expected.
- When is a bug a security issue? For example, a bug that only exists on the main branch and not in an official release of Exiv2 is a regular bug, not a security issue.
To create a security advisory, you need to be an administrator of the project. Go to the Security tab, click on the Security Advisories link, and you’ll see this green button (provided that you’re an admin):
GitHub Security Advisories have several cool features. When you create an advisory, it is initially in a draft state, which allows you to use it for private discussions about the vulnerability and to prepare the text of the advisory before you publish it. My favorite feature is that you can request a CVE. A CVE is a unique identification number for the vulnerability. Requesting a CVE used to be one of the more tedious parts of publishing an advisory, but now it’s just a button click. I also like the fact that the advisory has a Credit field for the person who reported the vulnerability. For example, this advisory is credited to @henices.
Temporary private forks are another cool feature. You can use them to collaborate on a fix, keeping the code changes private until you are ready to publish the advisory. The fork disappears after the advisory is published, so I can’t show you one, but this is an example of a merge commit that came from a temporary private fork. I have to admit that I have stopped using temporary private forks for Exiv2. They have a disadvantage: automated checks, like GitHub Actions, are not run. That’s because there’s a risk that an automated check could accidentally break the embargo on the vulnerability. For example, Exiv2 uses Codecov to check the code coverage of pull requests, which involves uploading code coverage data to Codecov. That’s a good thing normally—Codecov is a very useful tool for checking that new code is properly tested—but it might not be appropriate for a highly sensitive security fix that’s still under embargo. However, none of the vulnerabilities that have been found in Exiv2 recently are even remotely serious enough to warrant that level of secrecy. So I have been developing the fixes as regular (public) pull requests, to get the benefit of the automated checks. If I ever receive a PoC that achieves code execution in Exiv2, then I will use a temporary private fork to implement the fix.
This is the first blog in a four part series about hardening the security of Exiv2. This post was about using
SECURITY.md to define a security policy and about how to request a CVE and publish a security advisory. Please check back next week for part two, in which I pontificate about my three rules of bug fixing.
Follow GitHub Security Lab on Twitter for the latest in security research.
1 Having to provide a public email address is a common concern among maintainers. I realize that as a white man, I am at a much lower risk than some people of receiving abusive emails. Also, my email address is already easy to find in various places, such as my git commit history, so I do not think that publishing it in Exiv2’s security policy adds much additional risk.