Veteran whitehat Lucash-dev submitted a critical timelock vulnerability report in SharedStake’s timelock contracts to Immunefi on April 26. This vulnerability allowed the beneficiary of the timelocked funds to transfer out those funds before those funds were scheduled to be released.
At the time of the report, a total of $40m in SharedStake team funds could have been exploited by the intended recipients (the SharedStake core team) using this vulnerability. Because the only parties that could exploit this vulnerability were the SharedStake core team, the SharedStake team marked it with a vulnerability severity level of “High” and paid a $5000 bug bounty.
Unfortunately, some members of the SharedStake core team claim that a SharedStake insider, who was given access to the bug report by the SharedStake team, appears to have used the vulnerability to exploit the SharedStake contracts four times for approximately $500,000 on June 19 and June 23.
Immunefi cannot independently verify the narrative about which party or parties are responsible for the insider attack. We hope that all the SGT is returned to fixed timelocked contracts.
The SharedStake bug bounty program is on hold indefinitely pending completion of an exploit investigation. Until said investigation is completed to the satisfaction of Immunefi, the program will remain on hiatus.
04.26.2021 19:11 UTC — bug reported by whitehat Lucash-dev
04.29.2021 24:52 UTC — bug report confirmed by SharedStake, bug bounty paid
05.20.2021 16:18 UTC — SharedStake asks whitehat Lucash-dev for a bugfix
06.16.2021 19:36 UTC — fix delivered to SharedStake privately; SharedStake requests fix be submitted as a PR on the SharedStake Github, which he does
06.16.2021 20:00 UTC — SharedStake gives a new team member access to bug report
06.19.2021 05:06 UTC — SharedStake rogue insider tests exploit on mainnet — https://etherscan.io/tx/0x9400daa8711b4326e7b3bb7a4874099e5c7fe801c8b1488ff91bd6e5de332c9f
06.23.2021 05:00 UTC — SharedStake rogue insider exploits more timelocks on mainnet https://etherscan.io/tx/0x68dcf70e021684c414ec7512fd58b84098a020d62459b23f690f76a6ca6f38c5
Some of the resulting funds have been swapped to a mix of USDC and vETH2. Some remain held by the exploiter. Some have been staked.
It is not shown beyond a reasonable doubt that the new team member is the insider who went rogue, although some members of the ShareStake core team claim this.
Timelocked contracts work by releasing funds to a beneficiary who is entitled to those funds after certain timing conditions have been met. One practical example of a timelocked contract is a vesting contract, which releases funds on a set schedule to a particular beneficiary.
However, whitehat Lucash-dev discovered that it was possible to bypass timelock checks in the
SmartTimelock.sol contract and pull out all the funds immediately without governance approval by abusing the call method to invoke arbitrary external contract methods with arbitrary data. While the
onlyOwner modifier in the
call() method specified that only the beneficiary of the funds could call the function and SharedStake also checked the balance after the beneficiary called the
call() function to ensure that the current balance of the contract hadn’t decreased, an arbitrary message could have been sent to approve the beneficiary to move all the funds in a separate transaction.
The exploit can be illustrated in a step by step approach.
- Approve the transfer of funds, by executing the
call()method with following arguments:
to, which is the address of the token contract itself
b. Value = 0
data — ABI encoded arguments that state that all funds are approved for transfer to the beneficiary address. In Solidity code, it would look like
abi.encodeWithSelector(ERC20.approve.selector, address(owner), balance)
2. Call the token method
transferFrom() to move the token balance of the Timelock contract to the beneficiary
SharedStake was unable to implement the fix before an alleged SharedStake rogue insider was able to execute four attacks on the timelocked contracts using the vulnerability.
- Fix bugs quickly. Prioritize vulnerabilities that can lead to loss of funds. This bug was pending a fix for nearly 2 months. Anything impacting funds needs to be mitigated as soon as possible.
- Secure your development pipeline. Make sure you know the identities of all developers on your team. In the event of an insider attack, there may be only offline recourse. Offline recourse through the traditional legal system does not work effectively with anonymous team members.
- Smart contract vulnerabilities are highly sensitive information. Access should be on a need-to-know basis. Practice good information security and information hygiene.
- Ensure no team member can act unilaterally when managing protocol funds. Use of 3 out of 5 multisig is best practice.
- Transition away from admin keys for full decentralization.
DeFi projects have the unique ability to prevent insider attack by devolving control over the protocol to the community. Projects should take advantage of this to prevent precisely this kind of attack.