Brahma - ABA's results

Brahma Console is a custody and DeFi execution environment.

General Information

Platform: Code4rena

Start Date: 13/10/2023

Pot Size: $31,250 USDC

Total HM: 4

Participants: 51

Period: 7 days

Judge: 0xsomeone

Id: 295

League: ETH

Brahma

Findings Distribution

Researcher Performance

Rank: 1/51

Findings: 1

Award: $3,025.06

🌟 Selected for report: 1

πŸš€ Solo Findings: 0

Findings Information

🌟 Selected for report: ABA

Also found by: 0xmystery

Labels

bug
2 (Med Risk)
high quality report
primary issue
satisfactory
selected for report
sponsor confirmed
M-03

Awards

3025.0597 USDC - $3,025.06

External Links

Lines of code

https://github.com/code-423n4/2023-10-brahma/blob/main/contracts/src/libraries/TypeHashHelper.sol#L45-L50 https://github.com/code-423n4/2023-10-brahma/blob/main/contracts/src/libraries/TypeHashHelper.sol#L52-L57

Vulnerability details

Summary

When implementing EIP712, among other things, for data structures that will be a part of signing message a typehash must be defined.

The structure typehash is defined as:

typeHash = keccak256(encodeType(typeOf(s)))

  • where encodeType is the type of a struct that is encoded as:

name β€– "(" β€– member₁ β€– "," β€– memberβ‚‚ β€– "," β€– … β€– memberβ‚™ ")"

  • and each member is written as:

type β€– " " β€– name.

The project uses 2 structures on the signed data Transaction and Validation declared in TypeHashHelper:

    /**
     * @notice Structural representation of transaction details
     * @param operation type of operation
     * @param to address to send tx to
     * @param account address of safe
     * @param executor address of executor if executed via executor plugin, address(0) if executed via execTransaction
     * @param value txn value
     * @param nonce txn nonce
     * @param data txn callData
     */
    struct Transaction {
        uint8 operation;
        address to;
        address account;
        address executor;
        uint256 value;
        uint256 nonce;
        bytes data;
    }


    /**
     * @notice Type of validation struct to hash
     * @param expiryEpoch max time till validity of the signature
     * @param transactionStructHash txn digest generated using TypeHashHelper._buildTransactionStructHash()
     * @param policyHash policy commit hash of the safe account
     */
    struct Validation {
        uint32 expiryEpoch;
        bytes32 transactionStructHash;
        bytes32 policyHash;
    }

However, the precalculated typehash for each of the structure are of different structures:

    /**
     * @notice EIP712 typehash for transaction data
     * @dev keccak256("ExecutionParams(address to,uint256 value,bytes data,uint8 operation,address account,address executor,uint256 nonce)");
     */
    bytes32 public constant TRANSACTION_PARAMS_TYPEHASH =
        0xfd4628b53a91b366f1977138e2eda53b93c8f5cc74bda8440f108d7da1e99290;
    /**
     * @notice EIP712 typehash for validation data
     * @dev keccak256("ValidationParams(ExecutionParams executionParams,bytes32 policyHash,uint32 expiryEpoch)ExecutionParams(address to,uint256 value,bytes data,uint8 operation,address account,address executor,uint256 nonce)")
     */
    bytes32 public constant VALIDATION_PARAMS_TYPEHASH =
        0x0c7f653e0f641e41fbb4ed1440c7d0b08b8d2a19e1c35cfc98de2d47519e15b1;

POC

The issue went undetected in the initial development phase, and can be verified, because the tests still use the old hashes:

    function testValidateConstants() public {
        assertEq(
            TypeHashHelper.TRANSACTION_PARAMS_TYPEHASH,
            keccak256(
                "ExecutionParams(address to,uint256 value,bytes data,uint8 operation,address account,address executor,uint256 nonce)"
            )
        );
        assertEq(
            TypeHashHelper.VALIDATION_PARAMS_TYPEHASH,
            keccak256(
                "ValidationParams(ExecutionParams executionParams,bytes32 policyHash,uint32 expiryEpoch)ExecutionParams(address to,uint256 value,bytes data,uint8 operation,address account,address executor,uint256 nonce)"
            )
        );
    }

The specific test can be verified by running:

forge test --fork-url "https://eth-mainnet.g.alchemy.com/v2/<ALCHEMY_API_KEY>" -vvv --ffi --match-test testValidateConstants

Impact

Protocol is not EIP712 compliant which will result in issues with integrators.

Tools Used

Manual review and an online keccak256 checker for validating that the those hashes are not actually for the correct structures.

Recommendations

Modify the structure typehash (and tests) to point to the correct structures.

Assessed type

Other

#0 - c4-pre-sort

2023-10-20T21:12:24Z

raymondfam marked the issue as high quality report

#1 - c4-pre-sort

2023-10-20T21:12:30Z

raymondfam marked the issue as primary issue

#2 - c4-sponsor

2023-10-25T12:05:06Z

0xad1onchain (sponsor) confirmed

#3 - alex-ppg

2023-10-31T20:36:37Z

The Warden has demonstrated that the contract is non-compliant with EIP-712 as the type-hashes defined within it are outdated and incorrect.

The Warden has articulated what the potential impact is and, while slightly brief, the recommendation the Warden provided is correct.

As a result, I fully accept this submission as satisfactory as well as the best of its kind. #182 will be awarded partial credit given that it managed to pinpoint a single flaw in a single type-hash rather than identify that multiple type hashes were incorrect.

#4 - c4-judge

2023-10-31T20:36:43Z

alex-ppg marked the issue as satisfactory

#5 - c4-judge

2023-10-31T20:36:49Z

alex-ppg marked the issue as selected for report

#6 - 0xad1onchain

2023-11-19T05:53:50Z

Fixed, amended EIP 712 struct

AuditHub

A portfolio for auditors, a security profile for protocols, a hub for web3 security.

Built bymalatrax Β© 2024

Auditors

Browse

Contests

Browse

Get in touch

ContactTwitter