# function lockCapital() doesn't filter the expired protections first and code may lock more funds than required and expired defaulted protections may funded

lockCapital() sums active protections without expiring stale ones, so expired defaulted protections get funded and sellers lose more capital than owed.

- Payout: Contest reward
- Severity: medium
- Program: Carapace
- Credited: rvierdiiev
- Disclosed: 2023-02-01
- Write-up quality: 6/10
- Original: https://github.com/sherlock-audit/2023-02-carapace-judging/issues/305
- Library page: https://bugbountylibrary.com/r/sherlock%3A2023-02-carapace%3AM-1
- Tags: domain:web3 impact:funds-loss kind:contest platform:sherlock sev:medium tech:solidity technique:source-review vuln:accounting-error vuln:business-logic

**Target:** ProtectionPool.lockCapital() in credit default swap protocol
**Root cause:** lockCapital() iterates lendingPoolDetail.activeProtectionIndexes without first calling _accruePremiumAndExpireProtections(), so protections whose term has ended remain in the active set and are included in the locked amount.
**Steps:**
1. Buy protections on a lending pool; they enter activeProtectionIndexes.
2. Let time pass so some protections expire but _accruePremiumAndExpireProtections() is not invoked for that pool.
3. Trigger a default so DefaultStateManager calls lockCapital(_lendingPoolAddress).
4. Observe the loop sums min(protectionAmount, remainingPrincipal) for expired protections too, inflating _lockedAmount.
5. totalSTokenUnderlying is reduced by the inflated amount, locking more seller capital than required and paying expired defaulted protections.
**How found:** Code reading of lockCapital() noting it never calls the expiry routine that other flows use, and that inner principal calculation also lacks an expiry check.
**Exploitation:** No attacker action needed; occurs naturally when a default is processed before expired protections are pruned, causing excess seller funds to be locked and paid out to expired protection holders.
**Insight:** When a function iterates a stored 'active' set, check whether the set is pruned lazily elsewhere; any entry point that skips the pruning routine will over-count stale entries.
