On 07 April 2022, the Starstream Treasury was exploited leading to a loss of 532 million STARS. The attacker then deposited the stolen STARS tokens to Agora DeFi's lending contracts and borrowed multiple assets including METIS, WETH and MUSDC. The total protocol loss was ~$15,000,000.
Starstream is a suite of products for providing yield aggregation and yield generation on the Metis L2 rollup. The protocol is maintained by various developers and is governed by STARS holders.
On 07 April 2022, an attacker took advantage of an external function in the Starstream contract. An external function is able to be executed by any user. The external function execute() in the Starstream ‘Distributortreasury’ contract allowed the attacker to transfer STARS tokens from the Starstream treasury to the attacker’s account. The attacker then deposited the stolen STARS tokens into Agora DeFi’s lending contracts and borrowed assets including METIS, WETH and MUSDC. The attacker then used an Exchange Proxy to move the funds to the Ethereum blockchain before sending funds to Tornado Cash. In total the attacker sent 900 ETH to Tornado cash. A day later the attacker bridged 120 ETH back to the METIS network via the Metis Andromeda Bridge.
On 9 June 2022 Starstream announced via Twitter that they were winding down, stating that due to low usage of the protocol and the current market climate, the project was no longer viable.
“Starstream is winding down: All remaining treasury funds will be distributed to veSTARS holders and used for buybacks. veHERMES NFT will be merged with MaiaDAO and StarHermes will receive a 1:1 representation of the NFT via an airdrop.”
The root cause of this exploit is the Starstream Treasury contract's owner Distributor Treasury contract has an ‘external’ execute() function, which has a low-level call in the implementation. The ‘DistributorTreasury' is designed to distribute STARS in ‘StarstreamTreasury’. The attacker used this function to generate withdraw messages and withdraw STARS from 'StarstreamTreasury’.
function execute() has the ‘external’ property which allows external users to call it.
Using SkyTrace we can see the transfer of funds from the Exchange Proxy to Tornado cash.
Part of the auditing process of a smart contract is checking functions that have an 'external' flag legitimately need to have external access. As such the execute() function in Distributor Treasury contract would be detected and investigated further.