On 2020 May 10, Ondřej Vejpustek from TREZOR team sent us a PGP encrypted message containing a detailed explanation about a possible CoinJoin denial of service vulnerability, in complete accordance to our responsible security disclosure policy.
This document explains the timeline and actions taken by Wasabi developers until the resolution of the issue. We leave the technical explanation to Ondřej, himself, at the bottom of the post.

The vulnerability has been fixed and can no longer be exploited by a potential attacker.

Who’s affected?

Before the v4 Hard Fork, an attacker could have exploited the vulnerability to perform a DoS (denial-of-service) attack, in such a way that it was difficult to identify the attacker itself. Denial of Service means that the attacker would halt the entire CoinJoin process for all other participants and Wasabi rounds would no longer work. Given the fact that we have not observed any DoS attempts thus far, we assume that no Wasabi user has been affected by the vulnerability.

It is important to specify that the attacker could neither steal users’ funds nor deanonymize anyone. What they could have done was to prevent the completion of the CoinJoin process.

User Action

If you have already downloaded Wasabi Wallet v1.1.12, released on August 5th, 2020, then you are ready to take full advantage of the v4 Hard Fork; which fixed this vulnerability. In this case no user action is needed.

If you have not yet upgraded Wasabi to v1.1.12 version, then we urge you to do so; as the Hard Fork breaks the compatibility with older software.

Timeline

  • 2020, May 10: Ondřej  discloses the vulnerability to the Wasabi team.
  • 2020, May 11: Wasabi team confirms the existence of the vulnerability.
  • 2020, May 12: Wasabi team pays out a Bitcoin reward for the findings.
  • 2020, May 14: Wasabi team starts working on fixing the issue.
  • 2020, June 04: Wasabi team finalizes and then plans the deployment of the fix.
  • 2020, Aug 05: Wasabi Wallet v1.1.12 is released with the client side fix.
  • 2020, Sept 03: Wasabi Wallet v4 hard fork is deployed.

Closing Thoughts

Finally we’d like to thank you Ondřej and we hope your actions set the example for responsible review, notification and resolution of vulnerabilities.

Responsible Disclosure

Dear Adam,I found a severe security issue in your implementation of the coinjoincoordinator. An attacker can exploit the vulnerability to perform adenial-of-service attack such that it's extremely difficult to identifythe attacker.This paragraph summarizes how blind Schnorr signatures are used in yourimplementation. At the beginning of each round a fresh blind Schnorrsignature key pair is generated for every round level. In the inputregistration phase a participant of the coinjoin registers unspentoutputs in their possession as inputs to the coinjoin transaction andone or more blinded addresses as outputs of the coinjoin transaction. Inthe connection confirmation phase the coordinator determines how manylevels the participant has funds to participate in, and returns them thecorresponding number of blinded addresses signed with the correspondinglevel keys. In the output registration phase the participant (under adifferent identity) reveals their (unblinded) outputs with the(unblinded) signatures that are verified by the coordinator.A nonce that is used in blind Schnorr signatures is supposed to begenerated freshly for every signature. If a signer generates twosignatures using the same nonce, it's easy to determine their privatekey as same as the private part of the nonce.The problem is that the nonce in your implementation is part of the keypair. As a consequence the nonce is the same for all outputs registeredon the same level. That means that a participant that registers at leasttwo outputs on the same level is able to determine the signer's private key.Suppose h is a blinded message to be signed, d is the coordinator'sprivate key and r is the private part of the nonce.The signature of the blinded message is r - d * h modulo the order ofthe group that is used (secp256k1 in our case). Suppose an attacker hassignatures s1 and s2 of distinct messages h1 and h2 signed with the sameprivate key and nonce. Then the following holds:(s1 - s2) / (h2 - h1) = ((r - d * h1) - (r - d * h2)) / (h2 - h1)  = d * (h2 - h1) / (h2 - h1) = ds1 + h1 * d = (r - d * h1) + h1 * d = rAn attacker that knows the signer's private key can generate a validsignature for every message. Therefore, they are able to register anoutput that was never blind signed by the coordinator. What are theconsequences? As long as the implementation of the client is sound, theattacker can neither steal a decent amount of coins nor deanonymizeanyone. What they can do is prevent the completion of the coinjoin, inother words denial-of-service attack. I've got the following ideas:  * The attacker registers (in the output registration phase) both theirreal outputs and one or more fake outputs. Consequently, there are oneor more participants that aren't allowed to register their outputs sincethe output registration phase ends when there are as many registeredoutputs as returned blinded signatures in the connection confirmationphase. These participants naturally refuse to sign the conjointransaction. As a result, their unspent output registered as inputs tothe coinjoin are banned.  * The attacker registers only one of two of their real outputs. Besidethat, they register one fake output on a higher level. Because theyregistered as many outputs as they have been given blinded signatures,other participants can register their outputs. After that, thecoordinator builds a transaction that can't be valid, since the sum ofall inputs is less than the sum of all outputs. I didn't investigatewhat happens next.What are the possible fixes for this bug?  * The coordinator on request generates nonce pair, remembers bothprivate and public part, and returns the public one. A participant thatregisters their unspent outputs and blinded addresses uses the nonce toblind the addresses and sends the nonce in his request. The coordinatorfinds the corresponding private nonce, blind signs the addresses, andforgets the nonce pair, so it's not used repeatedly.  * Replace Schnorr blind signatures with RSA blind signatures, sinceRSA signature doesn't require nonce. I think you used RSA before.Nevertheless, I don't like this approach because RSA in contrasts withelliptic-curve cryptography isn't so widespread in the bitcoin community.I hope you appreciate this report!Best regards,Ondřej Vejpustek