# LUP is not recalculated after adding kicking penalty to pool's debt, so kick() updates the pool state with an outdated LUP

Ajna's kick() computed LUP before adding the 3-month kick penalty to pool debt, storing an outdated LUP and biasing interest-rate accounting.

- Payout: Contest reward
- Severity: high
- Program: Ajna
- Credited: Chinmay
- Disclosed: 2023-04-20
- Write-up quality: 7/10
- Original: https://github.com/sherlock-audit/2023-04-ajna-judging/issues/107
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-04-ajna%3AH-5
- Tags: domain:web3 impact:integrity kind:contest platform:sherlock sev:high tech:solidity technique:source-review vuln:accounting-error

**Target:** Ajna Pool.sol kick() / KickerActions._kick()
**Root cause:** _kick() computes kickResult_.lup via Deposits.getLup using poolState_.debt + additionalDebt_ before adding t0KickPenalty to t0PoolDebt, so the returned LUP excludes the penalty and is stale whenever the penalty is nonzero.
**Steps:**
1. Call `Pool.kick(borrower, npLimitIndex)` on an undercollateralized loan.
2. `KickerActions._kick()` sets `kickResult_.lup = Deposits.getLup(deposits_, poolState_.debt + additionalDebt_)` (additionalDebt_=0).
3. Then `vars.t0KickPenalty = wdiv(wmul(t0KickedDebt, rate), 4e18)` and `kickResult_.t0PoolDebt = poolState_.t0Debt + vars.t0KickPenalty`.
4. `Pool.kick()` calls `_updateInterestState(poolState, result.lup)` with the pre-penalty LUP.
5. Same stale LUP returned by `kickWithDeposit()` when `amountToDebitFromDeposit <= amountToCoverBond`.
**How found:** Code reading of _kick(): noticed LUP is computed for the _isCollateralized() check before the kick penalty is added to pool debt, and the same value is returned and persisted into interest state without recalculation.
**Insight:** When a function computes a derived value (LUP) for an early check and then mutates the inputs (adds penalty to debt), verify the value is recomputed before being persisted to state—stale derived values silently bias accounting.
