# Steal tokens from TempusController

TempusController trusted a caller-supplied tempusAMM contract, letting a fake AMM return arbitrary token addresses and share amounts to drain any ERC20 held by the controller.

- Payout: Audit contest
- Severity: high
- Program: Tempus Finance
- Found by: gpersoon
- Disclosed: 2021-11-08
- Write-up quality: 7/10
- Original: https://github.com/code-423n4/2021-10-tempus-findings/issues/10
- Library page: https://bugbountylibrary.com/r/c4%3A2021-10-tempus%3AH-01
- Tags: area:web3 domain:web3 impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** TempusController.depositAndProvideLiquidity / _depositAndProvideLiquidity
**Root cause:** depositAndProvideLiquidity accepts an arbitrary tempusAMM address and trusts its getVault/getPoolId/tempusPool return values without whitelisting, so a fake AMM controls ammTokens, mintedShares and sharesUsed used in the final safeTransfer.
**Steps:**
1. Deploy fakeVault with getPoolTokens(poolId) returning {TokenToSteal1,TokenToSteal2},{fakeBalance1,fakeBalance2},0; JoinPoolRequest() and joinPool() as no-ops.
2. Deploy fakePool with yieldBearingToken() returning fakeYieldBearingToken and deposit() returning fakeMintedShares.
3. Deploy fakeTempusAMM with getVault()=fakeVault, getPoolId()=0, tempusPool()=fakePool.
4. Call `depositAndProvideLiquidity(fakeTempusAMM,1,false)`; _getAMMDetailsAndEnsureInitialized returns fake vault/tokens, _deposit calls fakePool.deposit() returning fakeMintedShares, _provideLiquidity skips safeTransferFrom since sender==address(this).
5. Final line `ammTokens[0].safeTransfer(msg.sender, mintedShares - sharesUsed[0])` transfers arbitrary TokenToSteal1/2 amounts to attacker.
**How found:** Code reading of _depositAndProvideLiquidity: noticed the tempusAMM parameter is caller-controlled and its return values (ammTokens, mintedShares, sharesUsed) flow directly into a safeTransfer, so a fake contract could fabricate them.
**Exploitation:** Attacker deploys fake vault/pool/AMM contracts returning attacker-chosen token addresses and inflated mintedShares, then calls depositAndProvideLiquidity with the fake AMM; the controller's final safeTransfer sends any ERC20 it holds to msg.sender.
**Insight:** When a function takes a contract address as a parameter and later uses values returned by that contract to compute token transfers, treat the parameter as attacker-controlled data: trace every returned value into a transfer and check for a registry/whitelist.
