Caviar Private Pools - Evo's results

A fully on-chain NFT AMM that allows you to trade every NFT in a collection.

General Information

Platform: Code4rena

Start Date: 07/04/2023

Pot Size: $47,000 USDC

Total HM: 20

Participants: 120

Period: 6 days

Judge: GalloDaSballo

Total Solo HM: 4

Id: 230

League: ETH

Caviar

Findings Distribution

Researcher Performance

Rank: 49/120

Findings: 1

Award: $89.68

🌟 Selected for report: 0

🚀 Solo Findings: 0

Findings Information

🌟 Selected for report: Voyvoda

Also found by: 0xRobocop, Evo, Kenshin, Ruhum, giovannidisiena, philogy, sashik_eth, teawaterwire

Labels

bug
2 (Med Risk)
downgraded by judge
satisfactory
duplicate-569

Awards

89.6836 USDC - $89.68

External Links

Lines of code

https://github.com/code-423n4/2023-04-caviar/blob/main/src/EthRouter.sol#L129 https://github.com/code-423n4/2023-04-caviar/blob/main/src/PrivatePool.sol#L281 https://github.com/code-423n4/2023-04-caviar/blob/main/src/EthRouter.sol#L142

Vulnerability details

Impact

EthRouter provides or offers a way to execute a buy batch from PrivatePool, A user will try to call buy function in EthRouter to execute a buy operations against private pool, on EthRouter at L129 The buy function in PrivatePool will be triggered and executed, on buy function inside PrivatePool contract L281 a safeTransferETH will be called to transfer a royaltyFee to a recipient.

A recipient contract can call EthRouter buy function with empty parameters' on receive() function. Now buy function inside EthRouter contract will continue to line L142 and call safeTransferETH to transfer the balance of EthRouter to msg.sender. Therefore, the recipient steal the funds from EthRouter balance that's considered as refund for the buyer. eventually after a transfer made to the recipient contract the function buy inside the EthRouter will continue executing and will reach the line L142 to refund any surplus ETH to the caller buyer but the balance already gone and stolen by recipient attacker.

Proof of Concept

A simple scenario for the Reentrancy attack: let's name buy function on EthRouter as Ebuy, and buy function at PrivatePool as Pbuy for clarity.

  • Bob will call Ebuy function to execute a buy operation with 5 ETH.
  • Ebuy function eventually will call Pbuy function.
  • Pbuy will be executed and transfer the surplus ETH to EthRouter (assume it is 1 ETH)
  • Pbuy will transfer royaltyFee to the recipient Dave's contract.
  • Dave's contract is calling Ebuy on receive() function.
  • Ebuy will be called with empty params and a transfer of EthRouter's balance (1 ETH) will be sent to caller Dave's recipient contract
  • Bob's Ebuy call is continuing the process and execute the rest of the function
  • Bob doesn't receive his refund 1 ETH since it was stolen by Dave's contract.

Tools Used

Manual review

Use reentrancy guard.

#0 - c4-pre-sort

2023-04-20T17:37:17Z

0xSorryNotSorry marked the issue as duplicate of #752

#1 - c4-judge

2023-04-30T16:33:55Z

GalloDaSballo changed the severity to 2 (Med Risk)

#2 - c4-judge

2023-05-01T07:27:52Z

GalloDaSballo marked the issue as satisfactory

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax © 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter