# User can steal tokens by using duplicated ERC20 tokens as parameter in NounsDAOLogicV1Fork.quit

NounsDAO quit() didn't dedupe the ERC20 token list, so repeating one token address paid out its timelock share multiple times, draining funds.

- Payout: Contest reward
- Severity: high
- Program: Nouns DAO
- Credited: jasonxiale
- Disclosed: 2023-07-31
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2023-07-nounsdao-findings/issues/102
- Library page: https://bugbountylibrary.com/r/c4%3A2023-07-nounsdao%3AH-01
- Tags: domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** NounsDAOLogicV1Fork.quit governance contract
**Root cause:** quit() only checks each erc20TokensToInclude entry is whitelisted, not that the array is duplicate-free; quitInternal computes and sends a balance per array entry, so a repeated token is paid out repeatedly.
**Steps:**
1. Call `dao.quit(quitterTokens, tokensToInclude)` with `tokensToInclude = [token2, token2, token2]`
2. Each entry passes the isAddressIn whitelist check
3. quitInternal computes `balancesToSend[i] = timelock.balanceOf(token2) * tokenIds.length / totalSupply` for each of the 3 entries
4. timelock.sendERC20 pays token2 three times to msg.sender
5. Assert `token2.balanceOf(quitter) == 3 * (TOKEN2_BALANCE * 2) / 10`
**How found:** Code review of quit/quitInternal: noticed the whitelist loop validates membership but never uniqueness, while the payout loop iterates the raw user-supplied array — a classic duplicate-entry accounting gap.
**Exploitation:** A token holder calls quit() passing the same whitelisted ERC20 address N times; each duplicate entry yields a separate proportional payout from the timelock, multiplying the attacker's share and potentially draining the timelock's entire balance of that token.
**Escalation:** Repeating the address arbitrarily many times scales the payout toward full timelock balance drain.
**Insight:** When a user-supplied array drives per-element payouts, check whether membership validation implies uniqueness; any loop paying out per array entry without dedupe is a multiplier.
