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.