Closed code423n4 closed 2 years ago
As they point out, we explicitly recognized this as a known limitation going into the competition. We may make a modification here (and appreciate them writing up their perspective on this) but this is not a valid finding (and their proposed solution is incorrect)
As per the sponsor, I believe the finding to be invalid for two reasons:
Conduit
contract when no such contracts are meant to hold funds. I think in terms of minimising the attack surface, it makes sense to not have funds held by the Conduit
contract.
Lines of code
https://github.com/code-423n4/2022-05-opensea-seaport/blob/4140473b1f85d0df602548ad260b1739ddd734a5/contracts/lib/OrderFulfiller.sol#L244-L255
Vulnerability details
When fulfilling an order with
offerItem.itemType == ItemType.NATIVE
, the caller is required to send the native tokens for the offer item asmsg.value
.We believe this is a wrong design and can be used as a way to initiate phishing attacks targeting the pleb users.
When the caller calls
Consideration#fulfillOrder()/fulfillAdvancedOrder()
to fulfill or take an order, the call stack is:Consideration#fulfillOrder()/fulfillAdvancedOrder() -> OrderFulfiller#_validateAndFulfillAdvancedOrder() -> OrderFulfiller#_applyFractionsAndTransferEach() ->
https://github.com/code-423n4/2022-05-opensea-seaport/blob/4140473b1f85d0df602548ad260b1739ddd734a5/contracts/lib/OrderFulfiller.sol#L357-L363
The payments or considerations will be taken from the
msg.sender
to therecipient
.This makes the caller equals the buyer.
In the current implementation, the caller/buyer is required to pay for the offered native token item, which will go directly back to the caller within the transaction.
This is inherently meaningless, even if you consider the caller to be a exector contract, there is no point to ask for the native tokens just to send it back right away.
https://github.com/code-423n4/2022-05-opensea-seaport/blob/4140473b1f85d0df602548ad260b1739ddd734a5/contracts/lib/OrderFulfiller.sol#L233-L263
https://github.com/code-423n4/2022-05-opensea-seaport/blob/4140473b1f85d0df602548ad260b1739ddd734a5/contracts/lib/Executor.sol#L54-L63
A sophisticated attacker could create a sell order offering '100 ETH' for an NFT that usually trades at a lower price, and then send the link to a non-technical buyer.
The buyer has trust in the marketplace and was pleased with the price offered. So they called
fulfillOrder()
through the web UI, and their extension/hardware/mobile app wallet UI may display the100 ETH
in a funny way, the buyer thought that must be a friendly feature to show how much they are getting paid.So they clicked "Send", and the next thing they learned, was that's not really a friendly feature, and their precious NFT now belongs to the attacker.
Impact
We are aware that requiring the caller to pay for the offer item of native tokens is a designed/intended behavior, as you have clearly documented this in the Out of Scope section of the document.
However, we do not believe that this can be justified as an out-of-scope issue simply because it's an intended/designed behavior.
If it's a bad design that could cause users to lose money, it's a problem that needs to be addressed.
Recommendation
Consider making the following changes:
Conduit
contract to support depositing native tokens (Ether) and allowing a trusted caller to pull the native tokens from the Conduit contract and send them to a specified target. In essence, to build a special purposed wrapped ether contract.Conduit
to create an order withofferItem.itemType == ItemType.NATIVE
.