# An earner can still continue earning even after being removed from the approved list.

A disapproved M earner keeps accruing Earner Rate rewards because only the earner can call stopEarning, diluting other earners and excessOwedM to TTG vault.

- Payout: Contest reward
- Severity: medium
- Program: Mzero
- Credited: 00001111x0
- Disclosed: 2023-10-27
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-10-mzero-judging/issues/33
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-10-mzero%3AM-1
- Tags: domain:web3 impact:funds-loss impact:integrity kind:contest platform:sherlock sev:medium tech:solidity technique:source-review vuln:access-control vuln:business-logic

**Target:** MToken.sol / StableEarnerRateModel earner approval and rate logic
**Root cause:** stopEarning() is only callable by the earner themselves; removing an address from the EARNERS_LIST does not deactivate its earning index, so it continues accruing at the Earner Rate.
**Steps:**
1. Mint equal M balances to alice and bob; both call `startEarning()`.
2. Warp 1 day; both earn equal amounts.
3. Call `_registrar.removeFromList(TTGRegistrarReader.EARNERS_LIST, _alice)`.
4. Warp 1 day; alice still earns the same as bob despite being disapproved.
5. Only alice can call `stopEarning()`; after she does, earnerRate roughly doubles and bob's earnings double.
**How found:** Code review of MToken.startEarning/stopEarning and StableEarnerRateModel.rate(); noticed stopEarning is self-only and disapproval via registrar does not touch earning state, then wrote an integration test comparing alice vs bob across disapproval.
**Exploitation:** A disapproved earner simply never calls stopEarning(), continuing to accrue Earner Rate on their M balance, diluting rewards of legitimate earners and reducing excessOwedM routed to the TTG vault.
**Insight:** When a permission list gates an action, check whether revocation actually deactivates existing state; self-only stop functions leave stale accrual. Also note earner rate is inversely tied to totalEarningSupply, so a stuck earner dilutes everyone.
