Skip to content

What is a Reentrancy Attack?

A reentrancy attack is a specific type of vulnerability in smart contracts in which an external malicious contract exploits a vulnerability in another contract by repeatedly calling back into the vulnerable contract before a particular function finishes its execution. Let’s try to understand what exactly it means with an example.

Example of a vulnerable contract

Below is a simple solidity code which has a reentrancy vulnerability. Let’s understand how the attacker can exploit this contract –

contract Vault {
    mapping(address => uint) public balances;
    /// @dev Store ETH in the contract.
    function store() public payable {
        balances[msg.sender]+=msg.value;
    }
    /// @dev Redeem your ETH.
    function redeem() public {
        msg.sender.call{ value: balances[msg.sender] }("");
        balances[msg.sender]=0;
    }
}

Take a close look at the reedem function in the above example. Here, the balance is updated after the funds are sent to the user. An attacker can use this function to exploit the smart contract by calling the same function (reedem here) multiple times before the balance gets updated and he could eventually even drain the balance of the whole contract. This is the most classic case scenario of a reentrancy attack vulnerability.

🔥 Check this course out: Build a One Piece Personality dApp With Solidity

How to prevent Reentrancy attack

There are several ways to prevent reentrancy attacks in a smart contract. Let’s take a look at them

Checks-Effects-Interactions Pattern

The Checks-Effects-Interactions pattern is a best practice in smart contract development that helps prevent vulnerabilities like reentrancy attacks. This pattern defines a structured way to organize the code within a function to ensure than a certain checks and state changes are performed before interacting with external contracts or executing complex logic.

This ensures that the function checks for preconditions or requirements that must be met before proceeding with the execution and the state is updated when the conditions are met and then the transaction is executed.

The Check-Effects-Interaction pattern in the above example would change our code to the one shown below which eliminates the reentrancy attack.

contract Vault {
    mapping(address => uint) public balances;
    /// @dev Store ETH in the contract.
    function store() public payable {
        balances[msg.sender]+=msg.value;
    }
    /// @dev Redeem your ETH.
    function redeem() public {
        balances[msg.sender]=0;
        msg.sender.call{ value: balances[msg.sender] }("");
    }
}

Using Reentrancy Guard Contract

You can use a simple reentrancy guard contract like below in order to prevent your smart contract from vulnerability:

contract ReentrancyGuard {
    bool private _notEntered;

    modifier nonReentrant() {
        require(_notEntered, "ReentrancyGuard: reentrant call");
        _notEntered = false;
        _;
        _notEntered = true;
    }
}

Using the nonReentrant modifier, you can check if the function has been called once and prevent executing it again and again multiple times to exploit the contract.

Real-World Impact of Reentrancy Attacks

Several high-profile incidents have highlighted the devastating consequences these vulnerabilities can have. Here are a few examples:

  • The DAO Hack (2016): This infamous attack targeted The DAO, a decentralized autonomous organization built on the Ethereum blockchain. The DAO leveraged smart contracts to manage its funds. Hackers exploited a reentrancy vulnerability in the DAO’s contract, allowing them to siphon off over $60 million worth of Ether (ETH). This event significantly impacted the Ethereum ecosystem and led to a hard fork to recover the stolen funds.
  • Lendf.Me Exploit (2020): Lendf.Me, a decentralized lending protocol, fell victim to a reentrancy attack in April 2020. The attacker leveraged a vulnerability in the way ERC-777 tokens (a type of Ethereum token with additional functionalities) were handled. This resulted in the loss of over $25 million worth of cryptocurrency.
  • Cream Finance Attack (2021): Cream Finance, a DeFi (decentralized finance) platform, suffered a series of attacks throughout 2021. One of these attacks, in September 2021, exploited a reentrancy vulnerability, leading to the theft of approximately $18.8 million in various cryptocurrencies.

Conclusion

Reentrancy attack has been a reason for exploitation of a huge amount of crypto and is the most common vulnerability in smart contracts. But this common vulnerability still exists in smart contracts and needs to be taken care of before the contract is deployed. There are inbuilt contracts from Openzepplin which exists today to help prevent these vulnerabilities. But as a solidity developer, you should be aware of common vulnerabilities.

Try it out, ask us questions, and tell us how it went by tagging Metaschool on Social Media.

Follow us on –

🔮Twitter – https://twitter.com/0xmetaschool

🔗LinkedIn – https://www.linkedin.com/company/0xmetaschool/