Skip to content

Latest commit

 

History

History
119 lines (87 loc) · 4.08 KB

File metadata and controls

119 lines (87 loc) · 4.08 KB

Fun Crepe Lobster

High

Malicious admins will drain protocol funds through misconfigured market parameters

Summary

Improper validation of market configuration parameters will cause fund drainage vulnerability for the protocol as malicious or compromised admins will create markets with insufficient collateralization through parameter manipulation.

Root Cause

In ReputationMarket.sol:L242-L246 the validation checks for market configuration parameters do not ensure proper collateralization ratio between creation cost and maximum possible market liability.

Internal Pre-conditions

  1. Admin needs to call addMarketConfig() to set liquidity to be exactly 100
  2. Admin needs to set basePrice to be exactly MINIMUM_BASE_PRICE
  3. Admin needs to set creationCost to be less than maxVotes * basePrice
  4. Market needs to be active (not paused)

External Pre-conditions

  1. Admin account needs to be compromised or malicious
  2. Network gas cost need to be low enough for profitable exploitation

Attack Path

  1. Malicious admin adds new market config with minimum allowed parameters
  2. Admin sets extremely low creation cost relative to potential market size
  3. Users create markets with minimal collateralization
  4. Users can buy maximum votes allowed by LMSR formula
  5. Protocol becomes undercollateralized

Impact

The protocol suffers an approximate loss of up to (maxVotes * basePrice - creationCost) ETH per market. In the demonstrated configuration, markets require only 0.01 ETH collateral but can accumulate 1 ETH in liabilities.

PoC

pragma solidity 0.8.26;

import {ReputationMarket} from "./ReputationMarket.sol"; import {Test} from "forge-std/Test.sol";

contract MarketConfigExploit is Test { ReputationMarket public market; address public admin = address(0x1); address public user = address(0x2);

function setUp() public {
    // Deploy and setup market
    market = new ReputationMarket();
    market.initialize(
        address(this), // owner
        admin,         // admin
        address(0),    // signer
        address(0),    // verifier
        address(this)  // contract manager
    );
    
    // Fund user
    vm.deal(user, 1 ether);
}

function testConfigurationExploit() public {
    // Step 1: Admin adds dangerous config
    vm.startPrank(admin);
    
    uint256 minLiquidity = 100;
    uint256 minBasePrice = market.MINIMUM_BASE_PRICE();
    uint256 lowCreationCost = 0.01 ether;
    
    uint256 configIndex = market.addMarketConfig(
        minLiquidity,
        minBasePrice,
        lowCreationCost
    );
    
    // Step 2: Create market with minimal collateral
    vm.startPrank(user);
    market.createMarketWithConfig{value: lowCreationCost}(configIndex);
    
    // Calculate maximum market liability
    uint256 maxVotes = minLiquidity * 133; // LMSR limit
    uint256 maxLiability = maxVotes * minBasePrice;
    
    console.log("Market parameters:");
    console.log("Creation cost:", lowCreationCost);
    console.log("Max liability:", maxLiability);
    console.log("Collateralization ratio:", (lowCreationCost * 100) / maxLiability, "%");
    
    // Verify undercollateralization
    assertTrue(maxLiability > lowCreationCost, 
        "Market should be undercollateralized");
}

}

Mitigation

function addMarketConfig( uint256 liquidity, uint256 basePrice, uint256 creationCost ) public onlyAdmin whenNotPaused returns (uint256) { // Existing checks...

// Calculate maximum market liability
uint256 maxVotes = liquidity * 133; // LMSR limit
uint256 maxLiability = maxVotes * basePrice;

// Require minimum 150% collateralization
require(
    creationCost * 100 >= maxLiability * 150,
    "Insufficient collateralization ratio"
);

// Rest of the function...

}