#43528 [SC-Low] fund freeze scenario

Submitted on Apr 7th 2025 at 19:20:26 UTC by @Shahen for Audit Comp | Spectra Finance

  • Report ID: #43528

  • Report Type: Smart Contract

  • Report severity: Low

  • Target: https://github.com/immunefi-team/Spectra-Audit-Competition/blob/main/src/router/Dispatcher.sol

  • Impacts:

    • Temporary freezing of funds for at least 24 hour

Description

Brief/Intro

In the Dispatcher._dispatch() function, If the passed command is TRANSFER_NATIVE and the recipient cant accept native tokens, instead of reverting the whole transaction the native tokens will be stuck in the contract where Dispatcher.sol is inherited to. Mitigation is simple by checking the return value of the low-level call in L485 (Dispatcher.sol).

I have attached a coded foundry poc, Make a new test file under /test and paste the test code. Run forge test --match-path <testfile-name> -vvv

Vulnerability Details

Same as above brief intro

Impact Details

Freezing of native tokens if recipient address cant accept natives.

References

https://github.com/immunefi-team/Spectra-Audit-Competition/blob/1cebdc67a9276fd87105d13f302fd77d000d0c0b/src/router/Dispatcher.sol#L485

Proof of Concept

Proof of Concept

// SPDX-License-Identifier: BUSL-1.1

pragma solidity 0.8.20;

import "forge-std/Test.sol";
import {Dispatcher} from "../../src/router/Dispatcher.sol";
import {Commands} from "../../src/router/Commands.sol";


contract A is Dispatcher {

    constructor() Dispatcher(address(0x3)) {}
    function with_val(bytes calldata inputs) external payable {
        bytes1 commandType = bytes1(uint8(Commands.TRANSFER_NATIVE));
        _dispatch(commandType,inputs);
    }


}

contract B {
    //cant accept natives
}

contract freezeTest is Test {

   
    A public _a;
    B public _b;
    

    function setUp() public {
        
        _a = new A();
        _b = new B(); //recipient

    }


    function test_freeze() public {
        
        deal(address(this),1e18);
        assertEq(address(this).balance, 1e18);
        bytes memory _inputs = abi.encode(address(_b),uint256(1e18));


        //1. calls _dispatch() with command TRANSFER_NATIVE and a certain msg.value
        //2. If the recipient cant accept native tokens, instead of reverting the whole transaction the native tokens will be stuck in the contract where Dispatcher.sol is inherited to.
        _a.with_val{value: 1e18}(_inputs);
        assertEq(address(_a).balance, 1e18);
        assertEq(address(_b).balance, 0);

        //3. Mitigation is simple, check the return value of the lowlevel call in L485 (Dispatcher.sol)

    }

}

Was this helpful?