# A malicious user can set any contract as a local hToken for an underlying token since there is no access control for _addLocalToken

addLocalToken uses performCallOut instead of performSystemCallOut, letting anyone register an arbitrary contract as a local hToken and mint/bridge fake tokens.

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

**Target:** Branch Bridge Agent addLocalToken / root chain _addLocalToken cross-chain handler
**Root cause:** addLocalToken sends its cross-chain request via performCallOut instead of performSystemCallOut, so the system-request path (0x02) can be invoked directly by any user without going through the router, and _addLocalToken has no access control.
**Steps:**
1. Call branch bridge agent callOut with `_params = abi.encodePacked(bytes1(0x02), abi.encode(_underlyingAddress, anyContract, name, symbol))`
2. Root chain decodes funcId 0x02 and executes _addLocalToken, registering anyContract as the local hToken for _underlyingAddress
3. Since no mechanism exists to modify/delete local tokens, the mapping is permanently poisoned
4. If anyContract has mint, mint unlimited local hTokens and bridge them to receive global tokens at root
**How found:** Code review of addLocalToken noticed the last line uses performCallOut rather than performSystemCallOut, meaning the system-request funcId 0x02 could be submitted by any user directly, bypassing the router gate.
**Exploitation:** Attacker bypasses the intended branch-chain addLocalToken flow by directly invoking the system request path via performCallOut, registering a malicious or mintable contract as the local hToken; then mints local tokens and bridges them to drain global tokens, or bricks bridging of the underlying asset.
**Escalation:** Chosen contract type escalates impact: mintable ERC20 -> unlimited global token minting; empty-mint contract -> permanent DoS on bridging; malicious contract -> gas griefing / reentrancy surface.
**Insight:** When a protocol distinguishes user calls from system calls via a funcId prefix, check every cross-chain sender for performCallOut vs performSystemCallOut; a single wrong helper lets users forge system requests and hit privileged handlers like token registration.
