# Anyone can arbitrarily add router liquidity

Connext addLiquidity() trusts a router address parameter instead of msg.sender, letting anyone pull a router's approved ERC20 tokens into the contract.

- Payout: Audit contest
- Severity: high
- Program: Connext
- Found by: 0xRajeev
- Disclosed: 2021-08-30
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2021-07-connext-findings/issues/48
- Library page: https://bugbountylibrary.com/r/c4%3A2021-07-connext%3AH-01
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:evm tech:solidity technique:source-review vuln:access-control

**Target:** TransactionManager.sol addLiquidity()
**Root cause:** addLiquidity() takes an arbitrary router address and transfers that router's ERC20 tokens via transferFrom, rather than requiring router == msg.sender as removeLiquidity() does.
**Steps:**
1. Router has granted max approval of an ERC20 (assetID != 0) to TransactionManager.
2. Attacker calls `addLiquidity(router, assetID, amount)` passing the victim router's address.
3. Contract executes transferFrom(router, this, amount), pulling the router's tokens into the contract as liquidity.
**How found:** Code review comparing addLiquidity() (uses router param) against removeLiquidity() (uses msg.sender), spotting the missing access-control symmetry.
**Exploitation:** Any caller invokes addLiquidity with a victim router address and assetID != 0; the contract pulls the router's approved tokens into itself, forcing unwanted liquidity exposure. Router can later removeLiquidity to recover.
**Insight:** When one function derives the actor from msg.sender and its sibling takes an address parameter, diff the two: the parameterized one often lets anyone act on another user's approvals.

