DatingDapp

First Flight #33
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: low
Invalid

Reentrancy Vulnerability in executeTransaction

Summary

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.

Vulnerability Details

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.

(bool success, ) = payable(txn.to).call{value: txn.value}("");
require(success, "Transaction failed");
- emit TransactionExecuted(\_txId, txn.to, txn.value);

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.

txn.executed = true;
+ emit TransactionExecuted(\_txId, txn.to, txn.value);
(bool success, ) = payable(txn.to).call{value: txn.value}("");
require(success, "Transaction failed");

Impact

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.

Tools Used

  • Slither – Identified the reentrancy issue.

  • Manual Review – Confirmed the vulnerability and its impact.

Recommendations

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:

function executeTransaction(uint256 _txId) external onlyOwners {
require\_txId < transactions.length, "Invalid transaction ID");
Transaction storage txn = transactions[_txId];
require(!txn.executed, "Transaction already executed");
require(txn.approvedByOwner1 && txn.approvedByOwner2,"Not enough approvals"
);
txn.executed = true;
emit TransactionExecuted(_txId, txn.to, txn.value);
(bool success, ) = payable(txn.to).call{value: txn.value}("");
require(success, "Transaction failed");
}

Implement a Reentrancy Guard, using OpenZeppelin’s ReentrancyGuard to prevent reentrancy attacks.

import "@openzeppelin/contracts/security/ReentrancyGuard.sol";

contract MultiSigWallet is ReentrancyGuard {
}
  1. 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().

Updates

Appeal created

n0kto Lead Judge 7 months ago
Submission Judgement Published
Invalidated
Reason: Non-acceptable severity
Assigned finding tags:

invalid_reentrancy_with_no_impact

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.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.