# Defi Amm Cache Exploit Audit

> Audit DeFi AMMs for virtual balance cache exploitation vulnerabilities. Use this skill whenever you're reviewing AMM code, analyzing DeFi protocol security, investigating accounting bugs, or looking for cache-related exploits in weighted pools, stableswap implementations, or any protocol that caches derived state (virtual balances, TWAP snapshots, invariant helpers). Trigger this when users mention AMM audits, DeFi security reviews, cache invalidation issues, or when examining code with packed storage arrays and proportional updates.

- Skill: `abelrguezr/defi-amm-cache-exploit-audit` (Agent Skill, multi-file: 4 files)
- Install (CLI): `npx skillmds@latest add abelrguezr/defi-amm-cache-exploit-audit`
- Raw SKILL.md: https://api.skillmd.com/api/skills/abelrguezr/defi-amm-cache-exploit-audit/raw
- Safety review: pending
- Works with: Claude Code, Claude.ai, OpenAI Codex
- Category: Security
- Author: abelrguezr (https://skillmd.com/u/abelrguezr)
- Updated: 2026-09-10
- Page: https://skillmd.com/skills/abelrguezr/defi-amm-cache-exploit-audit

---


# DeFi AMM Cache Exploit Audit

This skill helps you identify and analyze **virtual balance cache exploitation** vulnerabilities in DeFi AMMs, where gas-saving caches are weaponized during boundary-state transitions.

## Vulnerability Pattern

The core issue: **Cached derived state is not reset when pool liquidity hits zero**, allowing attackers to poison the cache and mint inflated LP tokens on the "first deposit" after a full drain.

### Key Indicators

Look for these patterns in AMM code:

1. **Cached virtual balances** stored in packed arrays for gas efficiency
2. **Proportional updates** using floor division that leave rounding residues
3. **Missing cache reset** when `totalSupply == 0` or `totalLiquidity == 0`
4. **Initialization branches** that read cached values instead of recomputing from actual balances
5. **No sanity bounds** on mint amounts relative to actual deposits

## Detection Workflow

### Step 1: Identify Cached State

Search for storage patterns that cache derived values:

```solidity
// Red flags:
uint256[] packed_vbs;           // Virtual balances cache
uint256[] cached_rates;         // Oracle rate cache
uint256 invariant_helper;       // Cached invariant
uint256[] twap_snapshots;       // TWAP cache
```

### Step 2: Trace Update Logic

Find where caches are updated. Look for:

```solidity
// Vulnerable pattern: proportional decrement with truncation
packed_vbs[i] -= packed_vbs[i] * burnAmount / supplyBefore;

// Safe pattern: explicit reset on zero supply
if (totalSupply == 0) {
    for (uint256 i; i < tokens.length; ++i) packed_vbs[i] = 0;
}
```

### Step 3: Check Boundary Conditions

Examine initialization paths:

```solidity
// Vulnerable: trusts cache on first deposit
if (prevSupply == 0) {
    sumVb = _calc_vb_prod_sum();  // Reads stale cache!
}

// Safe: recomputes from ground truth
if (prevSupply == 0) {
    sumVb = _recompute_from_balances();  // Ignores cache
}
```

### Step 4: Verify Mint Bounds

Check if mint logic has sanity checks:

```solidity
// Missing: no bounds on mint amount
uint256 lpToMint = pricingInvariant(sumVb, prevSupply, amountsIn);

// Should have: revert if mint exceeds reasonable ratio
require(lpToMint <= depositValue * MAX_INIT_RATIO, "Mint ratio exceeded");
```

## Exploit Simulation

Use the included scripts to test for this vulnerability:

```bash
# Analyze Solidity code for cache patterns
python scripts/detect_cache_vulnerabilities.py <contract.sol>

# Simulate the exploit conditions
python scripts/simulate_cache_poison.py --config <config.json>
```

## Remediation Checklist

### Immediate Fixes

1. **Reset caches on zero supply**:
   ```solidity
   if (totalSupply == 0) {
       for (uint256 i; i < tokens.length; ++i) {
           packed_vbs[i] = 0;
       }
   }
   ```

2. **Recompute on initialization**:
   ```solidity
   if (prevSupply == 0) {
       // Ignore cache, compute from actual balances
       sumVb = _compute_from_actual_balances();
   }
   ```

3. **Add mint sanity bounds**:
   ```solidity
   uint256 maxMint = depositValue * 100; // 100x max ratio
   require(lpToMint <= maxMint, "Mint ratio exceeded");
   ```

### Long-term Improvements

- **Differential testing**: Recompute invariants off-chain with high-precision math after every state transition
- **Rounding residue drains**: Aggregate dust into treasury/burn to prevent cache drift
- **Runtime simulations**: Before critical operations, recompute from scratch and compare with cached values
- **Multi-transaction monitoring**: Track sequences of deposit/withdraw cycles that could poison state

## Real-World Case Study: yETH (Nov 2025)

**Impact**: ~$9M drained with only 16 wei of attacker capital

**Attack flow**:
1. Flash-loan multiple LSD assets (wstETH, rETH, cbETH, etc.)
2. Loop deposits/withdrawals to accumulate rounding residues in `packed_vbs[]`
3. Burn all LP tokens, setting `totalSupply == 0` while cache remains poisoned
4. Deposit 16 wei total across LSD slots
5. Pool reads stale cache, mints ~2.35×10²⁶ yETH
6. Redeem LP position, drain vault, repay flash loans

**Root cause**: `remove_liquidity()` used proportional decrements with floor division, leaving residues. `add_liquidity()` trusted the cache on first deposit instead of recomputing.

## Testing Strategy

### Unit Tests

```solidity
function testCacheResetOnZeroSupply() public {
    // 1. Add liquidity
    // 2. Remove liquidity in cycles to accumulate residues
    // 3. Burn final LP tokens (supply == 0)
    // 4. Assert: all cached values are zero
    // 5. Add new liquidity
    // 6. Assert: mint amount matches actual deposit value
}
```

### Fuzz Tests

- Fuzz deposit/withdraw cycles with varying amounts
- Check that `cached_value ≈ actual_value` within epsilon after each operation
- Test boundary: `totalSupply == 0` transitions
- Test mint ratio: `lpMinted / depositValue` should be bounded

## References

- [Check Point Research – The $9M yETH Exploit](https://research.checkpoint.com/2025/16-wei/)
- [Yearn Finance Post-Mortem](https://yearn.finance/blog/yeth-exploit)
- [DeFi Security: Cache Invalidation Patterns](https://github.com/consensys/slither/wiki/Cache-Invalidation)

