# An attacker can mint an arbitrary amount of hToken on RootChain

Unchecked uint8 cast of 257-element hTokens array in BranchBridgeAgent truncates length to 1, causing RootBridgeAgent to misparse and mint arbitrary hTokens.

- Payout: Contest reward
- Severity: high
- Program: Maia DAO Ecosystem
- Credited: Voyvoda
- Disclosed: 2023-09-18
- Write-up quality: 9/10
- Original: https://github.com/code-423n4/2023-05-maia-findings/issues/643
- Library page: https://bugbountylibrary.com/r/c4%3A2023-05-maia%3AH-12
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:chained technique:source-review vuln:accounting-error vuln:business-logic

**Target:** BranchBridgeAgent/RootBridgeAgent cross-chain deposit encoding
**Root cause:** callOutSignedAndBridgeMultiple packs hTokens.length via unsafe uint8 cast, so a 257-element array records length 1; downstream _bridgeInMultiple trusts that length and misaligns field offsets, letting attacker-controlled addresses be reinterpreted as amounts/deposits.
**Steps:**
1. Build DepositMultipleInput with 257 entries; all hTokens/tokens set to valid hToken and underlying, amounts/deposits all 0.
2. Set hTokens[1]=underlying token address, hTokens[2]=hTokens[3]=address(0x2FAF0800) (uint256 800000000).
3. Call `callOutSignedAndBridgeMultiple(params, dParams, remoteExecutionGas)` on BranchBridgeAgent.
4. packedData records length=1 due to `uint8(257)` overflow; _depositAndCallMultiple only checks array length equality, passes.
5. On RootChain, executeSignedWithDepositMultiple slices only 1 set (128 bytes); _bridgeInMultiple parses hTokens[0], tokens[0], amounts[0]=hTokens[2], deposits[0]=hTokens[3].
6. checkParams passes because hToken[0] is local and token[0] is underlying; bridgeToRoot mints `_deposit` (800000000) of global hToken to attacker's VirtualAccount.
**How found:** Code review of the packed encoding: noticed `uint8(_dParams.hTokens.length)` unsafe cast, then traced how the recorded length drives byte-slicing offsets in RootBridgeAgentExecutor._bridgeInMultiple, realizing misalignment lets array entries be reinterpreted as amounts/deposits.
**Exploitation:** Attacker needs only gas on a Branch Chain with a valid hToken/underlying pair. By padding the hTokens array to 257 entries and placing the desired mint amount as an address at indices 2 and 3, the truncated length causes RootBridgeAgent to read those addresses as amount/deposit, minting arbitrary hTokens to the attacker's VirtualAccount for free.
**Insight:** When a length field is packed with a narrowing cast (uint256->uint8), check whether downstream parsers use that length to compute fixed-stride offsets; a mismatch between the true array length and the encoded length lets you shift field boundaries so attacker-controlled addresses become numeric values.
