code-423n4 / 2022-05-opensea-seaport-findings

1 stars 0 forks source link

Caller always pays for ETH even for ETH offer items #171

Closed code423n4 closed 2 years ago

code423n4 commented 2 years ago

Lines of code

https://github.com/code-423n4/2022-05-opensea-seaport/blob/4140473b1f85d0df602548ad260b1739ddd734a5/reference/lib/ReferenceOrderFulfiller.sol#L218 https://github.com/code-423n4/2022-05-opensea-seaport/blob/4140473b1f85d0df602548ad260b1739ddd734a5/reference/lib/ReferenceExecutor.sol#L69

Vulnerability details

Impact

It's possible to create ItemType.NATIVE offer items that the offerer should pay for but this is not possible as only the caller (fulfiller) can send native tokens (ETH) when fulfilling an order. Therefore, this item type does not make sense in an offer. The fulfiller needs to pay for any NATIVE offer items which they then receive back.

It could be possible to trick someone into believing they would gain the NATIVE offer items.

Example

Create an order that looks like the fulfiller would receive the 100 ETH:

A fulfiller fulfills the order, has to pay 100ETH, receives back the 100ETH, but loses their NFT for free. Admittedly, they would need to set msg.value to 100 ETH but it could be that users / bots always send their entire balance because excess ETH is always refunded.

Recommended Mitigation Steps

Consider mitigating this phishing attack by validating that no order contains ItemType.NATIVE in their offer items.

0age commented 2 years ago

Native items like Ether are used as legitimate offer items in matchOrders as each order is explicitly supplied. The caller may also be routing native items from another source. This is also explicitly documented as a "known limitation" and therefore out of scope.

HardlyDifficult commented 2 years ago

From the out of scope section in the readme:

As Ether cannot be "taken" from an account, any order that contains Ether or other native tokens as an offer item (including "implied" mirror orders) must be supplied by the caller executing the order(s) as msg.value.