# Reentrancy guard in rageQuit() can be bypassed

PartyDAO rageQuit() reused rageQuitTimestamp as reentrancy guard; a host could reset it via setRageQuit() during token transfer and reenter to drain party funds.

- Payout: Contest reward
- Severity: medium
- Program: PartyDAO
- Credited: adriro
- Disclosed: 2023-06-23
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-05-party-findings/issues/13
- Library page: https://bugbountylibrary.com/r/c4%3A2023-05-party%3AM-06
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:medium tech:evm tech:solidity technique:chained technique:source-review vuln:access-control vuln:reentrancy

**Target:** PartyGovernanceNFT.rageQuit() / setRageQuit()
**Root cause:** rageQuit() deletes rageQuitTimestamp as a reentrancy guard, but setRageQuit() lets a host reset it to a future timestamp mid-execution, re-enabling reentrancy.
**Steps:**
1. Deploy malicious contract holding a host NFT and host role; party holds 1 ETH.
2. Victim calls `rageQuit(tokenIds, [maliciousToken, ETH], receiver)`.
3. During token transfer, malicious `transfer()` callback calls `party.setRageQuit(block.timestamp+1)` to clear the guard.
4. Callback calls `party.abdicateHost(attacker)` then reenters `party.rageQuit([hostTokenId],[ETH],attackerContract)`.
5. Fallback forwards drained ETH to attacker; victim receives 0.
**How found:** Code reading of rageQuit()'s reuse of rageQuitTimestamp as guard; noticed setRageQuit() could overwrite the zeroed guard during external calls, then adapted existing cannotReenter test into a PoC.
**Exploitation:** Attacker must be party host (or collude with one) and get a malicious ERC20 included in victim's withdrawTokens; during transfer callback resets rageQuitTimestamp, abdicates host, reenters rageQuit to withdraw ETH to attacker, draining party balance.
**Insight:** When a state variable doubles as a reentrancy lock, check every other function that writes it—any setter callable mid-execution (especially by privileged roles) defeats the guard; prefer a dedicated lock or a sentinel value that setters reject.
