For filling a partial order, because Seaport accepts any representation of a fraction, a malicious filler can provide a giant fraction (unreduced). This would severely limit what orders can be filled afterwards and in some cases making any more fills impossible.
Note: this is partially related to a high severity issue regarding truncation, allowing fillers to take more tokens than in the order, however in this case we highlight a griefing attack.
Note: this is more of an issue with the mechanism rather than implementation. The above bug in truncation allows "impossible fills" possible by some overflowing calculations truncating, however once the truncation bug is fixed, this issue would become relevant, unless the fraction mechanism is changed.
Alice places a partially fillable ETH order for 10 rare ERC1155 tokens as considerations.
Out of the 10 tokens, 5 of them are owned by Mallory and the remaining 5 are owned by 5 different individuals owning 1 each.
Mallory tries to fill 50% of the order (5 tokens), but instead of providing the fraction 1 / 2, Mallory provides 2**118 / 2**119.
Now, any order of the form a / b should satisfy that b == 2**119 (anything else would involve "cross multiplication" of the denominator which would make the denominator go beyond type(uint120).max). However, the only possible order is of the form 1 / 5, which can never be filled.
Mallory effectively made the remaining of the order unfillable.
The above griefing attack can also be extended by malicious users to prevent certain partial fills from happening by front-running orders.
Tools Used
Manual review
Recommended Mitigation Steps
Considering requiring that the fractions are in reduced form. This can be done by checking if gcd of numerator and denominator is 1. Here is an example implementation of GCD in Yul. However, this may not be enough to be bulletproof, there may still be further issues regarding overflows.
Lines of code
https://github.com/code-423n4/2022-05-opensea-seaport/blob/4140473b1f85d0df602548ad260b1739ddd734a5/reference/lib/ReferenceOrderValidator.sol#L215-L216
Vulnerability details
Impact
For filling a partial order, because Seaport accepts any representation of a fraction, a malicious filler can provide a giant fraction (unreduced). This would severely limit what orders can be filled afterwards and in some cases making any more fills impossible.
Note: this is partially related to a high severity issue regarding truncation, allowing fillers to take more tokens than in the order, however in this case we highlight a griefing attack. Note: this is more of an issue with the mechanism rather than implementation. The above bug in truncation allows "impossible fills" possible by some overflowing calculations truncating, however once the truncation bug is fixed, this issue would become relevant, unless the fraction mechanism is changed.
Proof of Concept
Context: ReferenceOrderValidator.sol#L215-L216
1 / 2
, Mallory provides2**118 / 2**119
.a / b
should satisfy thatb == 2**119
(anything else would involve "cross multiplication" of the denominator which would make the denominator go beyondtype(uint120).max
). However, the only possible order is of the form1 / 5
, which can never be filled.The above griefing attack can also be extended by malicious users to prevent certain partial fills from happening by front-running orders.
Tools Used
Manual review
Recommended Mitigation Steps
Considering requiring that the fractions are in reduced form. This can be done by checking if
gcd
ofnumerator
anddenominator
is 1. Here is an example implementation of GCD in Yul. However, this may not be enough to be bulletproof, there may still be further issues regarding overflows.