archethic-foundation / bug-bounty

Archethic Community Bug Bounty Program
4 stars 1 forks source link

[Bug]: Hardcoded uco price allows defi oracle attacks #63

Open cryptonoob2k opened 8 months ago

cryptonoob2k commented 8 months ago

Description

UCO.OracleChain (lib/archethic/oracle_chain.ex) uses get_uco_price method to retrieve current uco price, however if for some reason the node cant fetch price then returns a hardcoded price:

  def get_uco_price(date = %DateTime{}) do
    case MemTable.get_oracle_data("uco", date) do
      {:ok, prices, _} ->
        Enum.map(prices, fn {pair, price} -> {String.to_existing_atom(pair), price} end)

      _ ->
        [eur: 0.05, usd: 0.07]
    end
  end

This fallback mechanism allows txs to continue using this hardcoded price, leading to bad accounting and possibly allowing defi oracle attacks such as:

Attack Example scenario

Suppose current UCO price is 1 eur and the price oracles went down. An attacker takes advantage of this situation an tries to swap 100 euros (in a stable coin for example) for UCO:
Node returns 0.05 eur price for each uco, so the attacker receives 2000 UCOS instead of 100.

Severity

Critical

Platform

Linux

Version of Archethic apps

Latest version

Fix

Return an error and stop the tx if the price couldnt be fetched instead of a hardcoded price

Neylix commented 8 months ago

Hello Thank's for having interest in Archethic projects !

Your remark is valid, however this function does not fetch information from outside world, but it retrieves data from local information. The OracleChain.MemTable is a memory view of all oracle transaction that has been replicated. As oracle transaction are replicated on all the nodes, if there is at least one oracle transaction this function will always return a price and never goes in the fallback price.

The only time where the fallback prices are used is when a network bootstrap and until the first oracle transaction is done, or if you request a price before the bootstrap date of the blockchain.

So in some sense I think it's not possible for an attacker to make this function returning invalid price.

But to be more safe it could be a good idea to return an error if the requested date is before the first oracle transaction. This would means to adapt the validation of the first transaction of the network until the first oracle transaction is done.

Neylix commented 8 months ago

@samuelmanzanera What's your point of view for this subject ?

samuelmanzanera commented 8 months ago

Hello @cryptonoob2k . First of all you thanks for your contribution and dipe dive in our codebase; I'm totally agree with @Neylix, the function you highlighted is just a wrapper to read some cached data to make transaction validation faster. As mentioned by @Neylix , this table is filled by the latest oracle transactions, even when the node starts up. For more details you can look at this file: https://github.com/archethic-foundation/archethic-node/blob/develop/lib/archethic/oracle_chain/mem_table_loader.ex, this transaction are ingested and build the memory tables.

So this fallback is not actually possible except during bootstrap of the network which is not possible on the mainnet, or the node starts up without transaction ingestion to build memory tables or datetime manipulation. But in all the cases atomic commitment would help to resolve this issue by rejecting any inconsistent transaction.