56324 sc low missing from owner check in transferfrom verifier direct theft of user funds

Submitted on Oct 14th 2025 at 15:56:28 UTC by @Bug82427 for Audit Comp | Alchemix V3arrow-up-right

  • Report ID: #56324

  • Report Type: Smart Contract

  • Report severity: Low

  • Target: https://github.com/alchemix-finance/v3-poc/blob/immunefi_audit/src/utils/ZeroXSwapVerifier.sol

  • Impacts:

    • Direct theft of any user funds, whether at-rest or in-motion, other than unclaimed yield

Description

Brief/Intro

The verifier library fails to check the from address when validating transferFrom actions. An attacker can craft 0x calldata that contains transferFrom(token, victim, attacker, amount) and have it pass verification. If the victim previously approved the 0x Settler/aggregator, the Settler will pull tokens from the victim to the attacker in the same transaction. This results in immediate, direct theft of user funds.

Vulnerability Details

The library function _verifyTransferFrom decodes the transferFrom action and only verifies that the token equals targetToken. It does not verify that the from field equals the owner parameter passed to the verifier. Because of this, calldata that specifies from = victim and to = attacker will pass verification if token == targetToken.

 function _verifyTransferFrom(bytes memory action, address owner, address targetToken, uint256 targetAmount) internal view {
        (address token, , , uint256 amount) = abi.decode(
            _slice(action, 4),
            (address, address, address, uint256)
        );

        require(token == targetToken, "IT");
        // Removed balance check as the 0x quote already has slippage protection
    }```

## Impact Details
Impact type (in-scope): Direct theft of user funds (at-rest or in-motion).

Concrete loss: Attacker can move any amount up to the victim’s allowance for the Settler. If the victim granted a large allowance, the attacker can drain substantial funds instantly.

When funds are taken: In the same transaction that executes the Settler call (no waiting period).

Likelihood: High in real systems where users pre-approve aggregators .

Severity: Critical / High — direct transferable value theft with realistic preconditions.

## Proof of Concept

## Proof of Concept

// SPDX-License-Identifier: MIT pragma solidity ^0.8.18;

// Foundry test helpers import "forge-std/Test.sol";

/// @notice Minimal ERC20 for PoC (approve/transferFrom/mint) contract SimpleERC20 { string public name; string public symbol; uint8 public decimals = 18; uint256 public totalSupply;

}

/// @notice Mock Settler that executes TRANSFER_FROM action contract MockSettler { bytes4 private constant TRANSFER_FROM = 0x8d68a156;

}

/// @notice Vulnerable verifier contract (PoC — key behavior matches your library: missing from==owner check) contract ZeroXVerifier { bytes4 private constant EXECUTE_SELECTOR = 0xcf71ff4f; bytes4 private constant EXECUTE_META_TXN_SELECTOR = 0x0476baab; bytes4 private constant TRANSFER_FROM = 0x8d68a156;

}

/// @notice Gateway that uses verifier then forwards calldata to settler contract VerifierGateway { address public settler; address public verifier; address public targetToken; uint256 public maxSlippageBps;

}

/// @notice Foundry test demonstrating exploit contract ZeroXSwapTest is Test { SimpleERC20 token; MockSettler settler; ZeroXVerifier verifier; VerifierGateway gateway;

}

Was this helpful?