Lucene search

K
code423n4Code4renaCODE423N4:2023-10-ETHENA-FINDINGS-ISSUES-601
HistoryOct 30, 2023 - 12:00 a.m.

Minter can censor GATEKEEPER and mint uncollateralized for a prolonged period of time

2023-10-3000:00:00
Code4rena
github.com
2
ethena
gatekeeper
censorship
mev-boost
priority fee
uncollateralized minting
aws
ethereum
loss

7.2 High

AI Score

Confidence

High

Lines of code
<https://github.com/code-423n4/2023-10-ethena/blob/ee67d9b542642c9757a6b826c82d0cae60256509/contracts/EthenaMinting.sol#L277-L279&gt;
<https://github.com/code-423n4/2023-10-ethena/blob/ee67d9b542642c9757a6b826c82d0cae60256509/contracts/EthenaMinting.sol#L162-L187&gt;

Vulnerability details

Impact

Ethena explicitly mentions their protection against a compromised minter, the mentioned maximum loss is $100.000. The protection against a compromised minter rests on the GATEKEEPER role which is a system running on AWS set to remove the minter if mints happen under market value.

The issue here is that Ethereum has yet to implement censorship resistance which means that the GATEKEEPER’s transactions can be censored. This is even more plausible in a scenario when the attacker has insight in how the GATEKEEPER sets its priority fee which can be observed based on its previous transactions and based what common APIs would recommend based on the previous block. The attacker will also know the upper limit of what the GATEKEEPER can pay in priority fees since it can see its total balance.

The attacker has a budget of up to $100.000 to spend on each block since that is the revenue it can make minting USDe without depositing collateral.

The core issue is that an attacker can censor the GATEKEEPER by being a block builder for the 90% of blocks that use MEV-boost and the rest of the blocks can be censored by out-bidding the GATEKEEPER and consuming the entire available gas at a high gas price for each block.

The security system used to stop uncollateralised minting can therefore be circumvented. The attack can eventually be be stopped by a manual intervention from Ethena but significant damage can be made in short period. In 10 minutes ~5 million can be minted which 50x the assumed max loss.

Proof of Concept

The vulnerability rests on two claims:

  1. It is possible to censor the GATEKEEPER
  2. Censoring the GATEKEEPER can lead to significant losses
It is possible to censor the GATEKEEPER.

According to the documentation the GATEKEEPER is a system running on AWS submitting transactions if the minter misbehaves. The attacker will censor the GATEKEEPER by paying significantly more than expected to either build entire blocks or by consuming all gas available in a block at a high gas price. Observe that it is not likely that the base fee increases significantly during this attack since consuming the entire block gas limit is only necessary in ~10% of the blocks when MEV-boost is not used.

I will argue that this is possible by showing that a) it is possible to censor GATEKEEPER when the validator uses MEV-boost and b) it is possible to censor GATEKEEPER when MEV-boost in not used by the validator.

a) The average MEV-boost payment is ~0.05 ETH per block. Very large payments can happen but are very rare. Under normal circumstances the attacker could outbid other block builders with ~1 ETH per block and successfully censor the GATEKEEPER. At ~1800 USD/ETH the attacker profits ~$98200.

b) The validator not using MEV-boost mostly likely uses priority gas auctions to build the block. The attacker can successfully censor the GATEKEEPER by paying a large priority fee and consuming all available gas. Assuming base fee is 50 gwei, the attacker can pay significant priority + base fee at 200 gwei for 30M gas. At 1800 USD/ETH this would cost 30000000 * 200 * 1800/1e9 = $10800 . Since the attacker is minting $100.000 per block the attacker is still making a ~$90k profit.

Since 90% use MEV-boost the average cost of censorship would in (10800 + 1800 * 9)/10 = $2700 .

The actual price will depend on the circumstances when the attack is performed. In Table 1 below I show the profit and loss of funds based on how long it takes to stop the attack and the cost of censorship.

Censoring the GATEKEEPER can lead to significant losses.

How long this attack can continue is hard to reason about, this will depend on how fast Ethena can identify the issue and take manually control of the GATEKEEPER and outbid the attacker. Given that the GATEKEEPER is supposed to resolve this issue and since the attack can be performed when Ethena is less likely to notice, during a conference or team members are likely asleep I believe a 10m-30m is plausible.

In the POC below we mint the max amount for 10 minutes and deduct the cost of censorship.

Create a new file 2023-10-ethena/test/foundry/minting/tests/EthenaInfiniteMint.t.sol and paste the code below and run forge test --match-test testMintAttackPOC -vv.

// SPDX-License-Identifier: MIT
pragma solidity 0.8.19;

/* solhint-disable func-name-mixedcase  */

import "../EthenaMinting.utils.sol";

contract EthenaInfiniteMintTest is EthenaMintingUtils {

  // POC of funds lost and profits made based on
  // a 10 minute attack and a cost of $3000 per block 
  // to censor the gatekeeper
  function testMintAttackPOC() public {
    uint256 attackTime = 10; // In minutes
    uint256 averagePriceOfCensorship = 3000e18;

    uint256 blocksInAttack = attackTime*5;
    uint256 balanceBefore = usdeToken.balanceOf(beneficiary); 
    uint256 maxMintAmount = EthenaMintingContract.maxMintPerBlock();
    
    IEthenaMinting.Order memory bOrder;
    IEthenaMinting.Signature memory bTakerSignature;
    IEthenaMinting.Route memory bRoute;
    uint256 nonce;
    uint256 totalCost;

    for (uint256 currentBlock =1; currentBlock &lt;= blocksInAttack; currentBlock++){
      vm.roll(currentBlock);
      nonce++;

      (
        bOrder,
        bTakerSignature,
        bRoute
      ) = mint_setup(maxMintAmount, 1, nonce, true);

      vm.prank(minter);
      EthenaMintingContract.mint(bOrder, bRoute, bTakerSignature);
      totalCost+= averagePriceOfCensorship;
    } 

    uint256 balanceAfter = usdeToken.balanceOf(beneficiary); 
    uint256 totalMinted = balanceAfter-balanceBefore;
    
    console.log("Total non collateralized USDe minted:", totalMinted/1e18);
    console.log("Total profit for attacker in $:", (totalMinted - totalCost)/1e18);
  }

The table below shows the profit for the attacker and the total loss for Ethena based the duration of the attack and the average cost of censorship:

Cost/Minutes 10 20 30 40 50 60
$3,000 $4,850,000 $9,700,000 $14,550,000 $19,400,000 $24,250,000 $29,100,000
$5,000 $4,750,000 $9,500,000 $14,250,000 $19,000,000 $23,750,000 $28,500,000
$10,000 $4,500,000 $9,000,000 $13,500,000 $18,000,000 $22,500,000 $27,000,000
$50,000 $2,500,000 $5,000,000 $7,500,000 $10,000,000 $12,500,000 $15,000,000
$100,000 $0 $0 $0 $0 $0 $0
Total loss for Ethena $5,000,000 $10,000,000 $15,000,000 $2,000,000 $25,000,000 $30,000,000

Table 1. Source

This does not include the potential profit the attacker can make from shorting USDe. If de-pegging happens it will most likely not be due to swaps of minted tokens but due to panic selling if the attacker can freely mint for an extended period of time.

Actions taken by attacker:

When validator uses MEV-boost, bid to buy entire block to censor GATEKEEPER. Include the following transactions:

TX1: mint max amount of USDe and send to another account,
TX2: swap USDe on DEX for ETH.

When validator does not use MEV-boost, submit the following 3 transactions ordered based on
their priority fee to censor GATEKEEPER:

TX1: mint max amount of USDe and send it to another account
TX2: swap USDe for ETH.
TX3: call contract that loops and consumes the rest of the blocks gas.

TX3 calls a contract with the following functions:

  function infiniteLoop() public {
    uint256 x;
    while (true) {
      x++;
    }
  }

Tools Used

foundry, vscode, google sheets

Recommended Mitigation Steps

By using an oracle Ethena can guarantee a minimum valuation of deposited collateral for each USDe minted.

Add functionality in the minter() function that guarantees that a minimum amount of collateral has been deposited based on the current USD price of the collateral.

Assessed type

Invalid Validation

The text was updated successfully, but these errors were encountered:

All reactions

7.2 High

AI Score

Confidence

High