The contract implements a trading system where users can create and interact with offers. The createOffer
function allows users to create an initial offer, specifying details such as the number of points, amount, and trade tax. Once created, these offers can be listed for trading using the listOffer
function, making them available for other users (takers) to accept.
A critical vulnerability exists in the listOffer
function. When listing a protected offer, the function should update the offer's abort status to prevent the maker from aborting after takers have accepted. However, this status update is only performed in memory and not persisted to storage. As a result, malicious makers can exploit this oversight to create attractive offers, collect trade taxes from takers, and then abort the offers without fulfilling their obligations. This vulnerability undermines the integrity of the trading system and puts takers at risk of financial loss.
In the listOffer
function, when the offer type is protected, the abort status should be changed to AbortOfferStatus.SubOfferListed
. However, this change is only made in memory and not persisted to storage. This creates a discrepancy between the intended state and the actual state of the offer.
The abortAskOffer
function has the following requirements for aborting an offer:
The caller must be the offer authority.
The offer type must be Ask.
The abort offer status must be Initialized.
The offer status must be either Virgin or Canceled.
For Turbo settle type, the offer must not be a sub-offer (i.e., stockInfo.preOffer
must be address(0)).
The vulnerability in listOffer
allows a malicious maker to bypass the third requirement. When an offer is listed, its abort status should change from Initialized to SubOfferListed, preventing it from being aborted. However, because this status update doesn't persist to storage, the offer's abort status remains Initialized even after listing.
As a result malicious maker can list an offer, wait for takers to accept it and pay the trade tax, and then abort the offer. This allows the maker to get their initial collateral deposit and any collected trade taxes, without delivering the promised point tokens to the takers.
This vulnerability allows malicious makers to create offers with attractive rates and high trade taxes, collect taxes from takers, and then abort the offers without consequence.
As a result, the impact of this vulnerability includes
Financial Loss for Takers: Takers who accept these fraudulent offers and pay the trade tax will lose their money when the offer is aborted, as they will not receive the assets they paid for.
Erosion of Trust in the System: The integrity of the trading platform is compromised, as users cannot trust that offers will be honored after they are accepted.
Profit for Malicious Makers: Malicious makers can repeatedly exploit this vulnerability to profit from collected trade taxes without any intention of fulfilling their offers.
Alice (malicious maker) exploits this vulnerability:
Alice creates an offer with createOffer
, promising a high number of point tokens at a low price, setting a high trade tax.
Bob (taker) sees the attractive offer and calls createTaker
to accept it, paying the trade tax.
Bob calls listOffer
, but the abort status is not properly updated in storage.
Cathy (another taker) also accepts the offer and pays the trade tax.
Alice waits for more takers to accept the offer and pay trade taxes.
Alice calls abortAskOffer
, successfully aborting the offer despite it being listed.
Alice receives all collected trade taxes plus her original collateral deposit.
Alice can repeat this process multiple times, accumulating trade taxes from unsuspecting takers.
For testing the POC, run the following command:
Add the following code to the PreMarkets.t.sol
contract:
Manual Review
Foundry
To mitigated this issue ensure that the abort status is updated in the contract's storage, not just in memory. This can be done by modifying the listOffer function
Here is the recommended mitigation:
Valid high severity, because the `abortOfferStatus` of the offer is not updated and persist through `storage` when listing an offer for turbo mode within the `offerInfoMap` mapping, it allows premature abortion given the `abortOfferStatus` defaults to `Initialized`, allowing the bypass of this [check](https://github.com/Cyfrin/2024-08-tadle/blob/04fd8634701697184a3f3a5558b41c109866e5f8/src/core/PreMarkets.sol#L552-L557) here and allow complete refund of initial collateral + stealing of trade tax which can potentially be gamed for profits using multiple addresses
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.