# Anyone can steal protocol's llido assets and ether balance using its distributive functions

Missing access control on Goat Controller's claimRevenueShareDevTeam and earningPulls lets anyone drain LLido reserves and contract ETH to themselves.

- Payout: Contest reward
- Severity: high
- Program: Goat
- Credited: 0xumarkhatab
- Disclosed: 2024-06-12
- Write-up quality: 6/10
- Original: https://cdn.cantina.xyz/reports/cantina_competition_goat_mar2024.pdf#3.1.13
- Library page: https://bugbountylibrary.com/r/cantina%3Agoat_mar2024%3A3.1.13
- Tags: domain:web3 impact:funds-loss kind:contest platform:cantina sev:high tech:evm tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** Controller smart contract (claimRevenueShareDevTeam, earningPulls)
**Root cause:** claimRevenueShareDevTeam and earningPulls are public with no caller authorization; they pay out address(this).balance to msg.sender or attacker-controlled bountyPullerTo_.
**Steps:**
1. Call `Controller.claimRevenueShareDevTeam()` from any address; it sets account=msg.sender, runs earningWithdrawDevTeam, LLido.allToEth(0), then `payable(account).transfer(address(this).balance)`.
2. Alternatively call `earningPulls(account_, poolOwners_, bountyPullerTo_)` with attacker-controlled params; when bountyPullerTo_ != account_ it sells wsteth, converts weth to eth, and transfers full balance to bountyPullerTo_.
3. Repeat whenever contract holds LLido reserves or ETH.
**How found:** Code review of Controller's distributive functions revealed no msg.sender authorization checks and that payouts route to msg.sender or caller-supplied bountyPullerTo_.
**Exploitation:** Attacker directly invokes the unauthenticated public functions; internal calls are non-reverting so the payout path completes, transferring the contract's entire ETH balance (from LLido/wsteth conversion) to the attacker's address.
**Escalation:** MEV bots can front-run a legitimate caller's transaction from the mempool, simulate the ETH gain, and resubmit with higher gas and altered params, causing the legit tx to fail.
**Insight:** On payout/distribution functions, trace where the destination address comes from: if it's msg.sender or a caller-supplied param and there's no role check, the whole balance is claimable by anyone.
