Analyzing the Voting Amplification Vulnerability in Sushi Governance Contract
On Sep. 7, 2020, Jong Seok Park posted in this medium post describing a delegation double spending bug in the governance subsystem of SushiSwap. Upon receiving the notice, PeckShield researchers immediately analyzed the vulnerability and came up with this blog to further elaborate the technical details.
The bug is introduced by the SushiToken contract that fails to accompany
_moveDelegates() with every
transferFrom() call. Because of that, this bug might be exploited by a bad actor to double-spend
already delegated votes and launch the so-called Sybil attack to undermine
the SushiSwap’s governance.
For illustration, as shown in Figure 1, Bob can delegate his 100 SUSHIs’ votes to Charlie if
he has a balance of 100 SUSHIs. Now, Charlie can cast his 100 SUSHIs’ votes because of the delegation.
However, since the
transfer() handler of SushiToken fails to apply the logic
of moving delegates, Bob could transfer his 100 SUSHIs to his accomplice, Alice.
And Alice could delegate the votes of 100 SUSHIs to Charlie again!
This could repeat again and again by iterating the sending of 100 SUSHIs to Malice,
Trudy, Linda, and Eva with all of them re-delegating the same batch of SUSHIs votes to Charlie.
Eventually, Charlie can have the voting power of 100*N SUSHIs which actually
is backed by 100 SUSHIs only.
We started with the analysis of the
_delegate() helper routine that is invoked by
delegateBySig(), in the
As shown in Figure 2, the
delegate() helper allows the
delegateBalance of SUSHIs voting power to
delegateBalance is computed by the balance of SUSHIs owned by the
Based on that, a bad actor could launch the Sybil attack to undermine the governance subsystem by following the steps below. Here we assume Bob has 100 SUSHIs and all others have 0 SUSHI before the attack is launched:
|Action||Charlie’s Voting Power||Bob||Alice||Malice||Trudy|
|Bob delegates his 100 SUSHIs to Charlie||100||100||0||0||0|
|Bob transfers his 100 SUSHIs to Alice||100||0||100||0||0|
|Alice delegates her 100 SUSHIs to Charlie||200||0||100||0||0|
|Alice transfers her 100 SUSHIs to Malice||200||0||0||100||0|
|Malice delegates her 100 SUSHIs to Charlie||300||0||0||100||0|
|Malice transfers her 100 SUSHIs to Trudy||300||0||0||0||100|
|Trudy delegates her 100 SUSHIs to Charlie||400||0||0||0||100|
As a result, Charlie could have 400 SUSHIs’ voting power even though there is only 100 SUSHIs involved. By creating a large, arbitrary number of new addresses during the Sybil attack, the malicious actor can effectively amplify the voting powers even with a small number of SUSHIs in the play.
Comparison With YAM The reason why Bob could launch the attack in SushiSwap is due to the lack of accompanying
_moveDelegates() call in the
transferFrom() handlers of the
Specifically, SushiToken leverages the
OpenZeppelin’s ERC20 implementation
that does not have the above add-on. As a counter-example of the governance implementation,
the YAM token contract does perform
_moveDelegates() in each
|13:15:00 +UTC, Sep-7-2020||Park’s medium post released.|
|15:48:00 +UTC, Sep-7-2020||PeckShield’s report sent to SushiSwap team, including @SBF_Alameda.|
|15:59:59 +UTC, Sep-8-2020||PeckShield’s analysis blog published.|
PeckShield Inc. is an industry leading blockchain security company with the goal of elevating the security, privacy, and usability of current blockchain ecosystem. For any business or media inquiries (including the need for smart contract auditing), please contact us at telegram, twitter, or email.