In December 2021, the Grim Finance DeFi project was exploited via a reentrancy attack.  The attacker stole approximately $30 million in tokens from the contract.

Inside the Attack

The Grim Finance smart contract contained a reentrancy vulnerability in its safeTransferFrom function.  A function vulnerable to reentrancy does not properly update its internal state before sending a transfer to an external contract.  In Ethereum, a smart contract receiving a transfer can execute some code, which includes the ability to call the function sending the value again.  If that function hasn’t updated its internal state from the first call, this can result in incorrect behavior.

The vulnerable contract included a check of its value before and after the transfer.  The goal of this code pattern is to determine how much value the contract received and to provide the sender with the appropriate number of rewards.

In this case, Grim Finance provided enough gas to the malicious contract to perform reentrancy five different times and, on each iteration, the attacker transferred some value into the contract.  When the Grim Finance contract performed its “after” checks, the differences were cumulative.  

While the last reentrancy’s before and after check only encompassed a single transfer, the second-to-last reentrancy’s before check came before both the second-to-last and the last transfers, meaning that it saw double the transfer and provided double the reward.  With five reentrancies, the outermost loop could receive five times the reward that it should.

In the end, the attacker received many more rewards than it should have based on its deposits.  This enabled the attacker to drain the contract of $30 million in tokens.

Lessons Learned From the Attack

The Grim Finance attacker exploited a reentrancy vulnerability, which is not at all novel.  The most famous attack on Ethereum to date, the DAO hack, was a reentrancy exploit.  Coding best practices and protections against reentrancy exploits have existed for years, and this vulnerability should have been detected during a smart contract audit.

Rob Behnke