Cross-Function Reentrancy
In our last exploration of Dumb Code, we shed light on the dangerous simplicity of single-function reentrancy attacks. While mitigations like OpenZeppelin's reentrancy guard and the Checks - Effects - Interactions pattern (CEI) have helped to quell the frequency of these attacks, the landscape of smart contract security is ever-evolving and different types of reentrancy attacks are out there. Now, we will turn our focus to another complex facet of reentrancy vulnerabilities - cross-function reentrancy. Unlike the single-function variant where the attack continuously calls the same function, cross-function reentrancy opens up a new dimension of risk by exploiting the interconnectedness of different functions within a smart contract.
As we delve into this reentrancy variation, we'll uncover how cross-function reentrancy works, why it's particularly menacing, and the methods to fortify smart contracts against this sophisticated attack. Join me as we continue our journey into the deep and often murky waters of smart contract security, building on our understanding and striving towards a safer decentralized future.
The Vulnerability
Cross-function reentrancy is a more complex version of the single-function reentrancy vulnerability. It will involve multiple functions in a smart contract that share a state variable, and one or more of the functions update that state variable insecurely.
For example, any function that moves funds but updates balances after the transfer (does not follow the CEI pattern) yet is tagged with OpenZeppelin’s reentrancy guard could be vulnerable. While the reentrancy guard prevents that specific function from being reentered it won’t stop an attacker from hijacking the control flow if the vulnerable function is called from elsewhere within the contract.
Let’s take a look at an example. Below is an image that shows a cross-function reentrancy attack that I took from Valix.

In this example, the InsecureEtherVault can be drained by an Attacker who uses two malicious contracts to reenter the withdrawAll function by using a receive function in the attacking contract and the transfer function in the vault.
While the withdrawAll function utilizes the noReentrant modifier, thereby preventing a direct reentrancy attack on itself, it is not entirely secure. This is because the withdrawAll function does not update the withdrawing user's balance, userBalances[msg.sender] = 0, before sending Ether (Step 4). This opens a door for a sophisticated attacker to execute a cross-function reentrancy attack. By manipulating the control flow within the receive function of the 'Attack #1' contract, the attacker can transfer its balance (Step 5) to a second contract, referred to as 'Attack #2' (as shown in Figure 1).
From here, the attacker can initiate another transaction, calling the attackNext function in 'Attack #2' contract (Step 6), to incrementally draw Ether from the InsecureEtherVault contract and then channel the 'Attack #2' contract's balance back to the 'Attack #1' contract.
To drain all the Ether held in InsecureEtherVault, the attacker repeatedly alternates between executing the attackNext function in 'Attack #1' and 'Attack #2' contracts. The result? A successful heist of the entire vault. It's a clever, intricate attack that demonstrates the importance of rigorous security measures within smart contracts.
Conclusion
Cross-function reentrancy attacks serve as a poignant example of the complex vulnerabilities lurking within smart contracts. While these attacks can be intricate, they are easy to prevent by rigorously adhering to best practices such as following the CEI pattern. They can also be easily caught by static analyzers such as Slither. By ensuring that functions within a contract first verify all conditions, modify the state, and then engage in external interactions, developers can create a strong defense against this sophisticated attack.
In the rapidly evolving world of decentralized technology, understanding and implementing proven methodologies like CEI is crucial. It's a continuous journey towards innovation and security within smart contract development. Let's move forward with the knowledge and tools to create a robust and secure decentralized future.

