# Reentrancy attack possible on RootBridgeAgent.retrySettlement() with missing access control for RootBridgeAgentFactory.createBridgeAgent()

Missing lock on RootBridgeAgent.retrySettlement() plus permissionless createBridgeAgent() lets an attacker re-enter settlement and mint 5x local tokens from one deposit.

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

**Target:** RootBridgeAgent.retrySettlement / RootBridgeAgentFactory.createBridgeAgent (Solidity cross-chain bridge)
**Root cause:** retrySettlement() lacks a reentrancy lock and executionHistory[nonce] is set only after the executor call, violating CEI; createBridgeAgent() is permissionless so an attacker can inject a malicious BranchRouter that re-enters.
**Steps:**
1. Call RootBridgeAgentFactory.createBridgeAgent(attackerRouter) to deploy a RootBridgeAgent with attacker-controlled RootRouter.
2. Call rootCoreRouter.addBranchToBridgeAgent() to inject a malicious BranchRouter for a chain (e.g. FTM).
3. Initialize malicious BranchRouter with the created BranchBridgeAgent.
4. Mint/obtain hTokens and transfer them to attacker router.
5. Call callOutAndBridge with calldata encoding the rootBridgeAgent address to trigger anyExecuteSettlement on the malicious BranchRouter.
6. In anyExecuteSettlement, call rootBridgeAgent.retrySettlement{value:3e11}(sParams.settlementNonce, 1e11) recursively (4x) before executionHistory is set.
7. Top up BranchBridgeAgent gas each iteration; observe 5e19 local tokens minted from a single 1e19 settlement.
**How found:** Code review noticed retrySettlement() lacked the lock modifier used elsewhere and that createBridgeAgent() had no access control, then reasoned that a malicious BranchRouter callback could re-enter before executionHistory was set.
**Exploitation:** Attacker deploys a permissionless RootBridgeAgent with a malicious RootRouter, injects a malicious BranchRouter via addBranchToBridgeAgent, then initiates one settlement whose executor callback re-enters retrySettlement() four times before executionHistory[nonce] is marked, causing the same settlement to execute repeatedly and mint 5x the local tokens.
**Escalation:** Recursion limited only by gas; each re-entry re-executes the settlement, multiplying minted local tokens.
**Insight:** When a bridge marks executionHistory after calling an external executor, check whether the executor callback can re-enter the same settlement; also check factory functions that deploy agents with attacker-supplied routers for missing access control.
