# lack of access control in LendingLedger.sol#checkpoint_lender and function checkpoint_market

Unauthenticated checkpoint_market/checkpoint_lender let anyone pass a past timestamp, resetting epoch counters to 0 and zeroing out lenders' rewards.

- Payout: Contest reward
- Severity: high
- Program: Canto
- Credited: ladboy233
- Disclosed: 2023-10-11
- Write-up quality: 6/10
- Original: https://github.com/code-423n4/2023-08-verwa-findings/issues/142
- Library page: https://bugbountylibrary.com/r/c4%3A2023-08-verwa%3AH-07
- Tags: domain:web3 impact:dos impact:funds-loss kind:contest platform:code4rena sev:high tech:solidity technique:source-review vuln:access-control vuln:accounting-error vuln:business-logic

**Target:** LendingLedger.sol reward accounting contract
**Root cause:** checkpoint_market/checkpoint_lender lack access control and accept any valid epoch timestamp including past ones; _checkpoint_* sets lendingMarketTotalBalanceEpoch/lendingMarketBalancesEpoch to min(currEpoch, forwardTimestampLimit), allowing it to be decreased to 0.
**Steps:**
1. Call `checkpoint_market(market, 0)` and `checkpoint_lender(market, lender, 0)` with forwardTimestampLimit=0 (passes is_valid_epoch since 0 % WEEK == 0).
2. This sets lendingMarketTotalBalanceEpoch[_market] and lendingMarketBalancesEpoch[_market][_lender] to 0.
3. Subsequent sync_ledger/claim calls see lastMarketUpdateEpoch==0, skip the gap-fill loop, and rewards compute to 0.
**How found:** Noticed the checkpoint functions had no caller/market/timestamp validation and that _checkpoint_* unconditionally overwrites the epoch with min(currEpoch, forwardTimestampLimit), so a past timestamp could move the epoch backwards.
**Exploitation:** Attacker calls the two checkpoint functions with forwardTimestampLimit=0 at low gas cost, resetting epoch trackers; victim's sync_ledger/claim then yields 0 reward (POC shows 6 ETH reward dropping to 0).
**Insight:** When a 'checkpoint/lazy-update' function is permissionless, check whether the stored last-update epoch can move backwards; any min()/assignment without a monotonicity guard lets an attacker reset accounting state cheaply.
