Post-Mortem: 3/3/22 - 2x opportunities to win with a single PM ticket

This is a post-mortem document describing a critical [1] bug that was fixed recently on 3/3/22.

Summary

A vulnerability in the TicketBroker contract used to process winning tickets as a part of the probabilistic micropayment (PM) protocol was reported to the core team on 2/15/22 by @Czar102. This vulnerability, if exploited, would allow an orchestrator to have two opportunities to win (i.e. receive the face value of a ticket) using a single ticket received from a broadcaster.

The core team confirmed the issue within hours and over the course of the next two weeks implemented and validated a fix which was deployed on 3/3/22. The “Fix Timeline” section contains the rationale for the longer two week period that was used to implement and validate the fix.

Vulnerability

The TicketBroker contract uses the broadcaster’s signature over a ticket along with the pre-image of the recipientRandHash field of a ticket in order to generate a random number that is then used to determine if a ticket won or not.

Prior to Confluence, the OpenZeppelin ECDSA library used by the TicketBroker on L1 only accepted a single signature format. The TicketBroker contract deployed to L2 for the Confluence launch used an updated OpenZeppelin ECDSA library that accepted two signature formats - the first format is the standard “long” r, v, s signature format and the second format is the new EIP-2098 “short” r, vs signature format. Any long signature can be converted to a short signature and vice-versa. As a result, a broadcaster’s signature over a ticket has two distinct representations using these two formats and each of the signatures when used as an input into the TicketBroker random number generation function would result in a unique random number. This means that when an orchestrator receives a ticket and the broadcaster’s signature over the ticket, the broadcaster’s long signature represents an opportunity to win and the broadcaster’s short signature represents another opportunity to win - the orchestrator can simply take the broadcaster’s signature and apply a conversion algorithm to convert it to the other format. The TicketBroker contract would accept either signature format so if either of the two signatures resulted in a winning ticket the orchestrator would be able to submit the signature that resulted in a winning ticket to the TicketBroker.

An orchestrator that exploited this vulnerability would be able to generate a second signature for each broadcaster signature over a ticket. Given a long enough period of time during which the orchestrator is exploiting this vulnerability, the orchestrator be able to earn roughly 2x the number of winning tickets that it would otherwise earn without the exploit. As a result, the victim broadcaster would see 2x the amount of funds being drawn from its deposit/reserve during that same time period.

A few additional relevant notes:

  • An orchestrator would have needed to execute this exploit undetected over a period of time in order to successfully earn additional winning tickets from a broadcaster. The broadcaster would also need to consistently send work and tickets to the orchestrator during this period of time
  • This vulnerability would not have allowed someone to redeem a ticket twice

Detection

@Czar102 reported the vulnerability to the core team via Discord because at the time of the disclosure the Immunifi bug bounty program had not been launched yet.

Fix

The fix for the vulnerability was a single line require statement that disallowed the usage of the EIP-2098 short signature format for broadcaster signatures over tickets in the TicketBroker.

@Czar102 originally recommended only supporting the short signature format in the TicketBroker because the short signature format would make ticket redemption cheaper since the signature would requires fewer calldata bytes which is the most expensive resource in Arbitrum transactions today. However, the core team ultimately decided to instead only support the long signature format because removing support for the long signature format would have been a breaking change for all broadcasters and orchestrators since the node software exclusively uses the long signature format. This breaking change would have required all broadcasters and orchestrators to upgrade. In the interest of avoiding requiring broadcasters and orchestrators to upgrade on a short notice, the core team opted to only support the long signature format in the TicketBroker leaving a switch to the cheaper EIP-2098 short signature format as a gas optimization that can be considered as a part of a future upgrade.

Fix Timeline

2/15/22: @Czar102 reports the vulnerability via Discord
2/16/22: The core team confirms the vulnerability
2/16/22: The core team decides to take additional time to double check if there are other signature related issues in the TicketBroker before deploying a fix since the vulnerability would need to be exploited over a period of time in order to successfully extract additional funds from a broadcaster
2/16/22-3/2/22: The core team write additional test cases based on the vulnerability, implement the fix that passes the additional test cases, complete an internal review of the fix and complete an additional internal review of the signature logic in the TicketBroker as well as the OpenZeppelin ECDSA library
3/3/22: The core team deploys the fix

Lessons

The vulnerability could have been prevented with a more thorough review of the updated OpenZeppelin ECDSA library before deploying the TicketBroker to L2. In the future, the integration of dependency contract APIs will undergo a thorough code review - even if the contracts themselves have been audited, we should make sure that how the contracts are integrated/used do not create problems. With this vulnerability, there was not an actual bug in the ECDSA library, but the additional support of the EIP-2098 short signature format in the library created a problem with how the TicketBroker integrated the library.

Conclusion

The core team thanks @Czar102 for their responsible disclosure of this vulnerability which helped safeguard the funds of the Livepeer network and they have been awarded a $15k bug bounty (based on the recently updated guidelines for reward amounts of critical vulnerabilities which are now also incorporated into the bug bounty program) for this disclosure.

[1] As classified based on the severity system used for the Immunifi bug bounty program.