code4rena-2024-08-chakra-h09

[H-09] Inconsistent Handler Validation Behavior in Cairo ERC20Handler’s Cross-Chain Callback

보고서

Summary

Solidity 구현체에서는 핸들러가 유효하지 않을 때, 실패 상태를 기록하고 종료한다. Cairo 구현체에서는 핸들러가 유효하지 않을 때 트랜잭션을 취소시킨다. 체인별 동작의 불일치는 체인 별 상태의 불일치를 만들 것이다. 또한, Cairo 에서는 Solidity 구현과는 다르게 오류를 핸들링 할 수 없다.

Keyword

bridge, cross chain, business logic vul

Vulnerability

ERC20Handler의 Cairo 구현체에서 receive_cross_chain_callback 함수는 핸들러를 검증하기 위해 assert 문을 사용한다. 이로 인해 핸들러가 유효하지 않거나 허용 리스트에서 제거된 경우 트랜잭션이 취소된다. 이 동작은 Solidity 구현체와 다르다. Solidity 구현체는 유효하지 않은 핸들러에 대해 false를 반환한다.

Cairo 구현은 다음과 같다. 핸들러가 유효하지 않은 경우 트랜잭션을 취소한다. 트랜잭션은 현재 상태(대부분 Pending)로 유지된다.

fn receive_cross_chain_callback(ref self: ContractState, cross_chain_msg_id: felt252, from_chain: felt252, to_chain: felt252,
    from_handler: u256, to_handler: ContractAddress, cross_chain_msg_status: u8) -> bool{
    assert(to_handler == get_contract_address(),'error to_handler');
    assert(self.settlement_address.read() == get_caller_address(), 'not settlement');
@>  assert(self.support_handler.read((from_chain, from_handler)) && 
            self.support_handler.read((to_chain, contract_address_to_u256(to_handler))), 'not support handler');
 
    // ... rest of the function
}

Solidity 구현은 다음과 같다. 핸들러가 유효하지 않은 경우 트랜잭션을 취소하지 않고 상태를 기록한다.

function receive_cross_chain_callback(
    uint256 txid,
    string memory from_chain,
    uint256 from_handler,
    CrossChainMsgStatus status,
    uint8 /* sign_type */,
    bytes calldata /* signatures */
) external onlySettlement returns (bool) {
@>  if (is_valid_handler(from_chain, from_handler) == false) {
        return false;
    }
 
    // ... rest of the function
}
 
function processCrossChainCallback(
    uint256 txid,
    string memory from_chain,
    uint256 from_handler,
    address to_handler,
    CrossChainMsgStatus status,
    uint8 sign_type,
    bytes calldata signatures
) internal {
    require(
        create_cross_txs[txid].status == CrossChainMsgStatus.Pending,
        "Invalid transaction status"
    );
 
    if (
@>      ISettlementHandler(to_handler).receive_cross_chain_callback(
            txid,
            from_chain,
            from_handler,
            status,
            sign_type,
            signatures
        )
    ) {
        create_cross_txs[txid].status = status;
    } else {
@>      create_cross_txs[txid].status = CrossChainMsgStatus.Failed;
    }
}

Impact

이 취약점은 다음과 같은 문제를 초래할 수 있다.

  • Cairo 구현에서 거래가 무기한으로 대기 상태에 머물 수 있음
  • 다양한 체인 구현 간 거래 상태의 불일치
  • 크로스체인 운영의 잠재적 차단
  • 무효한 핸들러 시나리오의 처리 및 복구 어려움

Mitigation

Cairo 구현체를 Solidity 구현체와 동일하게 변경한다. 핸들러가 유효하지 않을 때 트랜잭션을 취소하지 말고 상태를 기록한다.

Memo

단순히 두 버전의 구현체가 다른 것이 취약점이 될 수 있나? 이런 이슈는 저지를 타는 것 같으니 일단 제출하는 게 나은 것 같다.


tags: bughunting, chakra, smart contract, starknet, cairo, bridge, cross chain, severity high, business-logic-vul