Responsible disclosure in the era of cryptocurrencies
Responsible disclosure in the era of cryptocurrencies
My experience disclosing a critical Bitcoin Cash vulnerability
On April 25, 2018, I anonymously and privately disclosed a critical vulnerability in Bitcoin Cash, one of the world’s most valuable cryptocurrencies — not to be confused with Bitcoin. A successful exploit of this vulnerability could have been so disruptive that transacting Bitcoin Cash safely would no longer be possible, completely undermining the utility (and thus the value) of the currency itself. Instead, the vulnerability was fixed without incident, and publicly disclosed on May 7, 2018.
A quick clarification: Bitcoin Cash is a cryptocurrency that is distinct from and incompatible with Bitcoin. It is named as such because it is derived from Bitcoin. The now-fixed bug described below only affected Bitcoin Cash; the only relation to Bitcoin is the similar name.
As for me and my motivations, I work for the Digital Currency Initiative at the MIT Media Lab, which as the name implies, is a group tasked with researching and developing cryptocurrencies. Specifically, I help develop and maintain Bitcoin Core, Bitcoin’s primary software implementation. Because of that work, I’m often asked at conferences and workshops what I consider to be Bitcoin’s greatest challenge in the future. My answer is always the same: avoiding catastrophic software bugs.
Working through this bug, which certainly had the potential for catastrophe, has reaffirmed my belief that the threat of software bugs is severely underestimated in the cryptocurrency world. I’m presenting a detailed report of this incident not as a slight against Bitcoin Cash, but as a real-world example of how much work is still required to reach the sophisticated level of engineering that cryptocurrencies require, and as a wake-up call to companies who have not adequately prepared for this type of scenario.
In short, a portion of the transaction signature verification code was rewritten, but the new code omitted a critical check of a specific bit in the signature type. I refer to that bit in the disclosure as SIGHASH_BUG. This omission would have allowed a specially crafted transaction to split the Bitcoin Cash blockchain into two incompatible chains. The next section describes the significance of such a split. For a detailed description of the bug and the fix, see the text of the disclosure itself.
What makes chain-splitting bugs so different?
Most cryptocurrencies, including Bitcoin and Bitcoin Cash, work by distributing a ledger of all transactions to all participants. In order to spend some coins, the spender must first create a transaction that obeys all of the rules of the system. Most of these rules are obvious and straightforward, for example “you can’t spend more than you have,” but others are much more subtle and technical, especially those which describe how digital signatures should be formatted. But if a cryptocurrency is permission-less, who sets these so-called validation rules?
Everyone collectively sets the validation rules!
The rules of the system are what everyone decides they are, and it is the software’s job to enforce them. If one participant tries to cheat and create a transaction that spends money that he doesn’t have, the other participants’ software will simply reject that transaction. For this reason, to ensure that a transaction will be universally accepted, it must obey even the most pedantic of rules.
The software tasked with enforcing the validation rules will always need to evolve. Changes are constantly being made to improve performance, add features, improve security, etc. It is critical, though, that the rules are enforced exactly the same way from one version to the next.
So what happens when an accidental programming bug in a new version of the software causes a transaction to be considered valid when all previous versions of the software reject it as invalid? The result is a “chain split,” and it means that only the subset of participants who have upgraded their software will accept the transaction in question. And since transactions and blocks are chained together, the two subsets will disagree on every transaction that follows. Without quick action from developers and a campaign to align all participants on one side of the fork or the other, the two camps of participants will never again be able to agree. At that point, the currency has effectively been split into two incompatible currencies — transacting as before will no longer possible.
Timing plays a crucial role when weighing the potential impact of bugs like these. If the chain is split such that 99% of participants are on one side with only 1% on the other, collectively siding with the majority is the obvious way forward. However, if roughly 50% have upgraded to the new version, there is no easy choice.
That type of chain-splitting bug is what I discovered in a new version of Bitcoin Cash’s most popular software implementation, but only after nearly half of the network had upgraded to it.
Because it is free and open-source software, Bitcoin Core is often used as a starting point for nascent cryptocurrencies. In addition to benefiting from years of refinement, sharing code means that otherwise unrelated cryptocurrencies can benefit from each other’s improvements going forward. Bitcoin Cash’s primary software implementation, called (again, confusingly) Bitcoin ABC, is one of those based on Bitcoin Core.
Due to the vast amount of common code, it is typical for these derivative projects to have similar bugs and therefore similar bugfixes. But it’s unrealistic to expect developers working on one currency to be proactive about sharing their improvements with developers working on others — just keeping up with one project is a tough enough job. For that reason, I’ve acquired a habit of going through some of those projects’ changes every few months to look for any bugfixes that might also be relevant to Bitcoin Core.
While looking through Bitcoin ABC’s change-logs earlier this year, I noticed that one of the most critical pieces of transaction validation had been refactored. The changes jumped out at me immediately because they seemed so unnecessary. Curious about the reasoning behind them, I took a look at the public review the changes had undergone. There was no justification other than “encapsulation,” it had only two reviewers, and review only lasted a week before the code was accepted.
Large refactors are very common and often good practice in typical software development. But it is extremely risky to modify validation code for cryptocurrencies, due to the ever-looming threat of inadvertently introducing a chain-splitting bug.
After seeing the minimal review the changes had undergone and the large number of lines changed, I thought it reasonably likely that a bug might have slipped in, and so I went looking. It took less than 10 minutes to find SIGHASH_BUG.
I mentioned above that my disclosure was anonymous. I’d like to explain the reasoning for that, as anonymity played a significant role in the process.
After verifying that the bug was trivially exploitable, I set out to notify the Bitcoin ABC developers — but quickly realized that I had a big problem. This was a bug in publicly-available, open-source software; any number of people could have already discovered it. There was nothing to stop anyone else from making the same discovery and taking advantage of it before a fix could be fully deployed.
So how might that play out, in the worst case scenario? Suppose that I privately disclosed the bug using my name — only for someone else to find it independently and exploit it anonymously the next day. Because I used my name for the disclosure, hard proof would exist that I had the knowledge and means to attack the network. I would have no way to prove that I was not the attacker. Then consider that, collectively, billions of dollars could have been lost as a result of this exploit. People have been killed for much less. So not only was anonymity important, I considered it a necessity for my safety.
While trying to figure out whether a completely anonymous disclosure was possible, I began to question whether it was worth the trouble at all. I had no obligation to report anything, after all. But if someone had discovered an equally nasty bug in Bitcoin Core, I would hope that person would bring it to our attention as discreetly and securely as possible. So I decided to do exactly that: create the report I would want to read, and deliver it as I would want to receive it.
The first step was obvious — I needed to track down Bitcoin ABC’s responsible disclosure policy. Policies for dealing with issues like these are commonplace these days, and are a must-have for any security-critical project. Sadly, I could find no such policy on its website or in its code repository. The closest I could find was displayed when submitting a bug to their github issues tracker:
For reporting security issues, please contact people privately.
Ugh, no help there. I then began trying to locate published encryption keys for “people” known to be Bitcoin ABC developers. Encrypting a message to them would ensure that no one else could view it — and thus I could worry less about how to deliver the message. I wouldn’t be able to actually verify the identities of the keyholders, but such an approach would still be reasonably secure and much better than no encryption at all.
But again, I hit a wall. There were no keys listed for any of the lead developers on the public PGP key servers where they would usually be found, and there were none present in their code repository either. At that point, I had no option other than to request keys anonymously through different online channels, using Tor to mask my identity as much as possible.
I first created a throwaway Github account and pinged a few Bitcoin ABC developers there on April 25:
“Could you please comment here with a gpg pubkey(s) so that I may responsibly disclose a sensitive bitcoin-abc vulnerability?”
Thankfully, this worked! I received a key about 5 hours later and quickly used it to respond with an encrypted detailed disclosure of the problem. When I came back the next day to check for a reply, however, Github had flagged my throwaway account, presumably due to my use of Tor. So further contact would not be possible there. I had to assume the disclosure was not received.
Now armed with a key for encryption, I decided to try one last avenue and submitted an encrypted message to Bitcoin ABC’s bug tracker, again using Tor and a throwaway account. Six hours later, after receiving no response, I made one last plea on their bug tracker:
“Ping. This is urgent, please acknowledge.”
On April 27, after waiting roughly 48 hours for a response to the disclosure, a pull request was opened to covertly fixed the issue in Bitcoin ABC. The message had apparently been received. Success!
The Bitcoin Cash vulnerability that I discovered was successfully disclosed and mitigated, and ultimately had no noticeable impact on the cryptocurrency. It would be a shame, though, if the ecosystem did not benefit from an analysis of such a substantial near-miss. As cryptocurrency developers, it is necessary to take a step back now and then to re-evaluate the tools at our disposal, as well as the policies and procedures that we put into place. We may not be able to eliminate the threat of bugs like these, but we can learn from them and be better prepared to handle them in the future. In an effort to kick-start a dialog on reducing risk, this follow-up post suggests some best-practices for now, as well as some active areas of research for the future.