The executeTransaction
function in the MultiSigWallet
contract is vulnerable to reentrancy
attacks because it makes an external call (call{value: txn.value})
before updating state variables or emitting events. A malicious contract can re-enter and potentially trigger another transaction execution before the first one completes, leading to double execution or unexpected state changes.
Code Snippet:
Attacker creates a malicious contract that has a fallback function capable of re-entering executeTransaction
.
The attacker gets a transaction approved and calls executeTransaction
.
The external .call{value: txn.value} sends funds to the attacker's contract.
The attacker's fallback function re-enters executeTransaction
before the first call completes, executing the same transaction multiple times before txn.executed = true
takes effect.
The attacker withdraws multiple times, effectively draining funds.
Medium Severity: Attackers can re-enter executeTransaction
before state changes take effect, leading to double execution or fund loss.
Funds Drain: If the attacker controls an approved transaction, they can continuously withdraw funds by exploiting the reentrancy loophole.
Broken MultiSig Security: A compromised owner or an attacker can bypass the intended transaction execution logic.
Slither (automated static analysis)
Manual Review (to confirm reentrancy risk)
To prevent reentrancy, follow the Checks-Effects-Interactions pattern by:
Updating state before making external calls (✅ Already done in this case).
Emitting events before making external calls (❌ Currently incorrect).
Using OpenZeppelin's ReentrancyGuard to prevent reentrancy.
Use ReentrancyGuard (nonReentrant modifier)
to prevent multiple function calls in the same transaction.
Emit events before external calls to ensure state consistency.
Limit gas for external calls to prevent complex fallback function execution.
By implementing these fixes, executeTransaction
will be secured against reentrancy attacks and prevent potential fund loss or double execution exploits.
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.