https://github.com/Cyfrin/2024-10-swan-dria/blob/main/contracts/swan/Swan.sol
The list function in the Swan contract is vulnerable to a reentrancy attack, potentially allowing attackers to exceed the maximum asset count per round and repeatedly invoke the transferRoyalties function, draining royalty funds. This vulnerability arises due to the lack of reentrancy protection in the function, coupled with an external call in transferRoyalties, which handles royalty transfers via ERC20 token transfers.
Exceeding Asset Count: By reentering the list function, attackers can bypass the maxAssetCount check, leading to an overflow of assets listed for a buyer in a particular round.
Royalty Drain: The transferRoyalties function transfers royalty fees via ERC20.transfer and ERC20.transferFrom. If reentered, it could result in multiple royalty payments, leading to fund depletion.
Deploy the Swan Contract with a configured ERC20 token for royalty transfers.
Create a malicious contract that calls the list function and reenters the function using the callback from the external transfer in transferRoyalties.
Observe the repeated execution of transferRoyalties, allowing royalty funds to be drained and asset count to be exceeded.
Manual Review
Use Reentrancy Guard: Add OpenZeppelin’s ReentrancyGuard to the contract and mark list as nonReentrant. This will prevent reentrant calls to the list function:
Check-Effects-Interactions Pattern: Refactor list to follow this pattern:
Check: Perform all validations first.
Effects: Update the contract’s internal state (e.g., mappings).
Interactions: Make external calls (like transferRoyalties) after state updates.
Separate Royalty Logic: Consider separating transferRoyalties into a separate function that can be manually invoked or called after listing, avoiding direct invocation within list.
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.