hats-finance / Thorn-protocol-0x1286ecdac50215a366458a14968fbca4bd95067d

GNU General Public License v3.0
0 stars 0 forks source link

# High Severity Security Report: Invalid Token Address Vulnerability #94

Open hats-bug-reporter[bot] opened 1 month ago

hats-bug-reporter[bot] commented 1 month ago

Github username: @catellaTech Twitter username: catellatech Submission hash (on-chain): 0x51dfd7962bb30986e963847f3a33ba0513a2c950db36b8ca922659b5e5fc6427 Severity: high

Description:

Issue Description

A critical vulnerability has been identified in the StableSwapRouter and StableSwapFactory contracts. These contracts fail to validate whether the addresses provided for token operations correspond to actual token contracts. This oversight allows the creation of swap pairs and the execution of swaps involving invalid token addresses, potentially leading to loss of funds, contract state corruption, or other unexpected behaviors.

Severity: High

Impact: This vulnerability could result in:

  1. Creation of invalid swap pairs
  2. Execution of swaps with non-existent tokens
  3. Potential loss of funds
  4. Misleading contract state
  5. Degraded user experience and loss of trust

Proof of Concept (PoC)

The following test case demonstrates the vulnerability:

function testInvalidTokenAddressVulnerability() public {
    console.log("\n--- Starting Invalid Token Address Vulnerability Test ---");

    // Deploy a new token
    Token validToken = new Token("Valid Token", "VALID", 18);
    validToken.mint(address(this), 1000000);
    console.log("Valid token deployed at:", address(validToken));

    // Create an invalid token address (EOA)
    address invalidToken = address(0x1234);
    console.log("Invalid token address (EOA):", invalidToken);

    // Try to create a pool with the invalid token
    console.log("Attempting to create a pool with invalid token...");
    vm.expectRevert();
    stableSwapFactory.createSwapPair(address(validToken), invalidToken, A, Fee, AdminFee);
    console.log("Pool creation attempt completed");

    // Attempt to perform a swap
    address[] memory path = new address[](2);
    path[0] = address(validToken);
    path[1] = invalidToken;

    uint256[] memory poolTypes = new uint256[](1);
    poolTypes[0] = 2;

    uint256 swapAmount = 1000;
    validToken.approve(address(stableSwapRouter), swapAmount);
    console.log("Approved router to spend", swapAmount, "of valid token");

    console.log("Attempting swap with invalid token...");
    vm.expectRevert();
    stableSwapRouter.exactInputStableSwap(path, poolTypes, swapAmount, 0, address(this));
    console.log("Swap attempt completed");

    // Check balances to ensure no tokens were transferred
    uint256 balanceAfter = validToken.balanceOf(address(this));
    console.log("Balance of valid token after attempted swap:", balanceAfter);
    assertEq(balanceAfter, 1000000, "Tokens should not have been transferred");

    // Try to get swap amounts for the invalid pair
    console.log("Attempting to get input swap amount for invalid pair...");
    vm.expectRevert();
    stableSwapRouter.getInputStableSwap(path, poolTypes, swapAmount, 1000000);
    console.log("getInputStableSwap attempt completed");

    console.log("Attempting to get output swap amount for invalid pair...");
    vm.expectRevert();
    stableSwapRouter.getOutputStableSwap(path, poolTypes, swapAmount, 0);
    console.log("getOutputStableSwap attempt completed");

    console.log("--- Invalid Token Address Vulnerability Test Completed ---\n");
}

--- Starting Invalid Token Address Vulnerability Test --- Valid token deployed at: 0x212224D2F2d262cd093eE13240ca4873fcCBbA3C Invalid token address (EOA): 0x0000000000000000000000000000000000001234 Attempting to create a pool with invalid token... Pool creation attempt completed Approved router to spend 1000 of valid token Attempting swap with invalid token... Swap attempt completed Balance of valid token after attempted swap: 1000000 Attempting to get input swap amount for invalid pair... getInputStableSwap attempt completed Attempting to get output swap amount for invalid pair... getOutputStableSwap attempt completed --- Invalid Token Address Vulnerability Test Completed ---


This PoC demonstrates that the contracts do not properly validate token addresses, allowing operations with invalid tokens to proceed without appropriate safeguards.

## Mitigation Recommendations

1. **Implement Token Address Validation**: Add a function to check if an address contains contract code and implements the ERC20 interface. Use this function before any token operations:

```solidity
function isValidToken(address token) internal view returns (bool) {
    if (token == address(0)) return false;
    if (token.code.length == 0) return false;
    try IERC20(token).totalSupply() returns (uint256) {
        return true;
    } catch {
        return false;
    }
}
  1. Modify Critical Functions: Update functions like createSwapPair, exactInputStableSwap, and others to use the isValidToken check:
function createSwapPair(address tokenA, address tokenB, ...) external {
    require(isValidToken(tokenA) && isValidToken(tokenB), "Invalid token address");
    // Rest of the function
}
  1. Input Validation: Add checks at the beginning of functions that interact with tokens to ensure all addresses in the path array are valid tokens. check the token lenght of the path.

By implementing these mitigations, the contracts will be better protected against invalid token addresses, significantly reducing the risk of unexpected behaviors and potential loss of funds.

catellaTech commented 1 month ago

So, basically all the following contracts: |-- StableSwapLP.sol |-- StableSwapLPFactory.sol |-- StableSwapThreePoolDeployer.sol |-- StableSwapTwoPoolDeployer.sol No check in the token lenght. So, please add the proper require: require(token.code.length > 0, "Invalid token");