The DatingDapp MultiSig Wallet is a contract that manages shared funds between matched users. The contract allows users to execute transactions once both parties approve. However, a reentrancy vulnerability was identified in the executeTransaction
function due to an external call (call{value: txn.value}
) occurring before the TransactionExecuted
event emission. This could allow an attacker to re-enter the function and execute unintended transactions before the event is logged.
The Issue is Reentrancy in MultiSigWallet.executeTransaction
detected by Slither
Reference: Slither Detector Documentation("")
Root Cause is the function makes an external call (call{value: txn.value}
) to transfer ETH before emitting the TransactionExecuted
event.
This introduces a potential reentrancy vulnerability, as an attacker could execute a malicious contract that re-enters executeTransaction
before the state change is fully completed.
Fixed Code
State changes setting txn.executed = true
occur before the external call.
The event is emitted before transferring funds, ensuring visibility in case of failures.
Unauthorized ETH withdrawals: If exploited, an attacker could re-enter executeTransaction
and execute multiple unintended transactions before state changes are finalized.
Fund manipulation: Attackers could drain the multisig wallet by executing malicious reentrant calls.
Breaks intended use case: The dating escrow system relies on secure fund handling, and this bug could disrupt user trust by enabling unintended withdrawals.
Slither – Identified the reentrancy issue.
Manual Review – Confirmed the vulnerability and its impact.
Use the Checks-Effects-Interactions Pattern
Reorder state changes before external calls.
Emit events before making external calls to improve security.
Ensure txn.executed
is updated before calling call{value: txn.value
}.
Fixed Code:
Implement a Reentrancy Guard, using OpenZeppelin’s ReentrancyGuard to prevent reentrancy attacks.
import "@openzeppelin/contracts/security/ReentrancyGuard.sol";
Consider using transfer()
or send()
instead of call{value: txn.value
} to limit gas usage for external contract execution.
Alternatively, use a reentrancy-safe withdraw pattern where users manually withdraw funds instead of receiving them via call()
.
matchRewards: Contract is created just before and is the one called. No impact. executeTransaction: CEI is followed. Emitting an event in disorder is informational in that context. withdraw: CEI is followed.
The contest is live. Earn rewards by submitting a finding.
This is your time to appeal against judgements on your submissions.
Appeals are being carefully reviewed by our judges.