Skip to main content

lending

Auto-loaded by defi-auditor agent during Phase 2 when analyzing lending protocols. Provides patterns for: liquidation logic, interest rate models, collateral management, health factor calculations, bad debt handling. Core vulnerabilities: self-liquidation, precision loss, oracle manipulation, collateral factor attacks.

الانتقال إلى التثبيت

معلومات المصدر

المستودع
BitterSecurity/Vigilo
آخر نشاط في المصدر
٢ فبراير ٢٠٢٦ في ٠٧:١٥
لغة SKILL.md المكتشفة
الإنجليزية
النجوم
٦٦
التفرعات
١٧

خيارات التثبيت

يُحدَّد Prompt الذي يراجع المصدر أولًا بشكل افتراضي. يمكنك التبديل إلى أمر مباشر أو تنزيل نسخة محلية.

مراجعة ملفات المصدر

اقرأ SKILL.md وأي ملفات مرافقة يعرضها SkillsMP قبل أن تقرر التثبيت.

عرض SKILL.md

SKILL.md
تعليمات المصدر · معاينة للقراءة فقط
name
lending
description
Auto-loaded by defi-auditor agent during Phase 2 when analyzing lending protocols. Provides patterns for: liquidation logic, interest rate models, collateral management, health factor calculations, bad debt handling. Core vulnerabilities: self-liquidation, precision loss, oracle manipulation, collateral factor attacks.
user-invocable
false
# Lending Protocol Patterns This skill provides comprehensive knowledge for auditing DeFi lending protocols. ## Core Lending Concepts | Concept | Description | |---------|-------------| | Collateral Factor | Max borrow % against collateral | | Liquidation Threshold | Health level triggering liquidation | | Utilization Rate | Borrowed / Total Supplied | | Interest Rate | Function of utilization | | Health Factor | Collateral value / Debt value | --- ## Why Lending Protocol Attacks Happen (Root Causes) ### Root Cause 1: Health Factor Calculation Timing The fundamental vulnerability: health factors computed from stale or cached data instead of real-time prices. ```solidity // VULNERABLE: Cached health factor mapping(address => uint256) public healthFactors; function liquidate(address user) external { // Uses stale cached value require(healthFactors[user] < 1e18); // Actual health factor may be different! } // SECURE: Compute in real-time function liquidate(address user) external { uint256 collateralValue = getCollateralValue(user); // Real-time oracle uint256 debtValue = getDebtValue(user); uint256 healthFactor = collateralValue * 1e18 / debtValue; require(healthFactor < 1e18); } ``` **Attacker's view**: "The protocol checks a stale health factor. I can manipulate prices between the check and liquidation, or liquidate users who are actually safe." ### Root Cause 2: Liquidation Incentive Misconfiguration Liquidation bonus set higher than the safety margin, making self-liquidation profitable. ```solidity // VULNERABLE: Bonus exceeds safety margin uint256 constant MAX_LTV = 80e16; // 80% uint256 constant LIQUIDATION_BONUS = 15e16; // 15% // Attacker borrows at 80% LTV, self-liquidates with 15% bonus // Net profit: 15% - (100% - 80%) = -5%... wait, this is a loss // But if bonus > (100% - LTV), it's profitable! uint256 constant LIQUIDATION_BONUS = 25e16; // 25% (DANGEROUS!) // Profit: 25% - 20% = 5% free money ``` **Attacker's view**: "I borrow at max LTV, wait for any price movement, then self-liquidate and pocket the bonus." ### Root Cause 3: Interest Precision Loss Small amounts round to zero during interest accrual, allowing dust attacks or precision exploits. ```solidity // VULNERABLE: Interest rounds to 0 uint256 interest = principal * rate / SECONDS_PER_YEAR; // If principal * rate < SECONDS_PER_YEAR, interest = 0 // Example: principal = 100 wei, rate = 1e16 (1%) // interest = 100 * 1e16 / 31536000 = 0 (rounds down) // SECURE: Use high-precision accumulator uint256 interestAccumulator; // Ray (1e27) precision uint256 newAccumulator = oldAccumulator + (rate * 1e27 / SECONDS_PER_YEAR); ``` **Attacker's view**: "I can deposit tiny amounts that accrue zero interest, or exploit rounding to avoid paying interest on small borrows." ### Root Cause 4: Collateral Valuation Trust Collateral value depends entirely on oracle accuracy. Stale, manipulated, or incorrect oracles break the entire protocol. ```solidity // VULNERABLE: Single oracle, no staleness check function getCollateralValue(address user) public view returns (uint256) { uint256 price = oracle.getPrice(collateralToken); // Could be stale! return userBalance * price / 1e18; } // SECURE: Validate oracle freshness function getCollateralValue(address user) public view returns (uint256) { (uint256 price, uint256 timestamp) = oracle.getPriceWithTimestamp(collateralToken); require(block.timestamp - timestamp <= MAX_STALENESS); return userBalance * price / 1e18; } ``` **Attacker's view**: "If I can manipulate the oracle or use a stale price, I can inflate collateral value and borrow more than safe." ### Root Cause 5: Bad Debt Socialization Gap When liquidation fails to recover full debt, bad debt accumulates and is socialized across remaining suppliers, creating insolvency. ```solidity // VULNERABLE: No bad debt handling function liquidate(address user) external { uint256 collateralValue = getCollateralValue(user); uint256 debtValue = getDebtValue(user); // If collateral < debt, bad debt remains! // Suppliers lose money } // SECURE: Handle underwater positions function liquidate(address user) external { uint256 collateralValue = getCollateralValue(user); uint256 debtValue = getDebtValue(user); if (collateralValue < debtValue) { uint256 badDebt = debtValue - collateralValue; // Socialize or use insurance fund insuranceFund -= min(badDebt, insuranceFund); } } ``` **Attacker's view**: "If I can create a position where collateral < debt, the protocol becomes insolvent and I profit from the socialized loss." --- ## Liquidation Vulnerabilities ### 1. Profitable Self-Liquidation **Root Cause**: Root Cause 2 (Liquidation Incentive Misconfiguration) **Vulnerable Pattern:** ```solidity // DANGEROUS: Liquidator bonus too high uint256 constant LIQUIDATION_BONUS = 15e16; // 15% function liquidate(address user, uint256 repayAmount) external { // Attacker can: // 1. Borrow at 80% LTV // 2. Wait for tiny price drop // 3. Self-liquidate with 15% bonus // = Free 15% - (100% - 80%) = Net profit! } ``` **Check:** Liquidation bonus should be less than (100% - Max LTV). ### 2. Liquidation Cascade ```solidity // When one liquidation triggers another // Large position liquidated → price drops → more liquidations // Mitigations: // - Gradual liquidation (partial) // - Circuit breakers // - Liquidation delays ``` ### 3. Bad Debt Accumulation **Root Cause**: Root Cause 5 (Bad Debt Socialization Gap) **Vulnerable Pattern:** ```solidity // DANGEROUS: No bad debt handling function liquidate(address user) external { // If collateral < debt after liquidation // Bad debt remains in protocol // Eventually becomes insolvent } // SECURE: Handle underwater positions function liquidate(address user) external { uint256 collateralValue = getCollateralValue(user); uint256 debtValue = getDebtValue(user); if (collateralValue < debtValue) { // Socialize bad debt or use insurance fund uint256 badDebt = debtValue - collateralValue; insuranceFund -= min(badDebt, insuranceFund); } } ``` --- ## Interest Rate Model ### Standard Jump Rate Model ```solidity contract JumpRateModel { uint256 public baseRate; // Rate at 0% utilization uint256 public multiplier; // Rate increase per utilization uint256 public jumpMultiplier; // Rate increase above kink uint256 public kink; // Utilization % where jump occurs function getBorrowRate(uint256 cash, uint256 borrows) public view returns (uint256) { uint256 utilization = borrows * 1e18 / (cash + borrows); if (utilization <= kink) { return baseRate + utilization * multiplier / 1e18; } else { uint256 normalRate = baseRate + kink * multiplier / 1e18; uint256 excessUtil = utilization - kink; return normalRate + excessUtil * jumpMultiplier / 1e18; } } } ``` ### Interest Rate Vulnerabilities **1. Rate Manipulation** ```solidity // Attacker can manipulate utilization // 1. Flash loan large amount // 2. Deposit → lower utilization → lower rates // 3. Borrow at low rate // 4. Withdraw and repay flash loan ``` **2. Precision Loss** **Root Cause**: Root Cause 3 (Interest Precision Loss) ```solidity // DANGEROUS: Interest rounds to 0 for small amounts uint256 interest = principal * rate / SECONDS_PER_YEAR; // If principal * rate < SECONDS_PER_YEAR, interest = 0 // SOLUTION: Accumulate interest with high precision uint256 interestAccumulator; // Ray (1e27) precision ``` --- ## Collateral Vulnerabilities ### 1. Collateral Factor Changes ```solidity // DANGEROUS: Instant collateral factor reduction function setCollateralFactor(address token, uint256 newFactor) external { collateralFactors[token] = newFactor; // Existing borrowers may become instantly liquidatable! } // SECURE: Grace period or gradual reduction function setCollateralFactor(address token, uint256 newFactor) external { require(newFactor >= collateralFactors[token] - MAX_DECREASE); pendingFactors[token] = newFactor; factorEffectiveTime[token] = block.timestamp + TIMELOCK; } ``` ### 2. Collateral Oracle Manipulation **Root Cause**: Root Cause 4 (Collateral Valuation Trust) ```solidity // Collateral valued using manipulable oracle // Attacker inflates collateral value → borrows more → profits // See oracle vulnerability patterns ``` ### 3. Toxic Collateral ```solidity // Collateral that can't be liquidated: // - Pausable tokens // - Blacklistable tokens // - Low liquidity tokens // Mitigation: Whitelist collateral carefully ``` --- ## Borrowing Vulnerabilities ### 1. Borrow Cap Bypass ```solidity // VULNERABLE: Cap checked only on new borrows function borrow(uint256 amount) external { require(totalBorrowed + amount <= borrowCap); // Interest accrual can push over cap! } // Check on any state-changing operation ``` ### 2. Same-Block Borrow-Repay ```solidity // EXPLOIT: Borrow and repay in same block // No interest accrued = free leverage function borrow(uint256 amount) external { require(lastBorrowBlock[msg.sender] < block.number); lastBorrowBlock[msg.sender] = block.number; // ... } ``` --- ## Health Factor Calculations ### Standard Formula ``` Health Factor = (Collateral Value × LTV) / Debt Value Health Factor > 1: Safe Health Factor < 1: Liquidatable ``` ### Vulnerabilities **1. Stale Health Factor** **Root Cause**: Root Cause 1 (Health Factor Calculation Timing) ```solidity // DANGEROUS: Cached health factor mapping(address => uint256) public healthFactors; // Health factors become stale as prices change // Always compute in real-time ``` **2. Rounding Direction** ```solidity // SECURE: Round health factor DOWN (safer) uint256 healthFactor = collateralValue * 1e18 / debtValue; // Round debt UP when calculating uint256 debt = (borrowed * (1e18 + interest) + 1e18 - 1) / 1e18; ``` --- ## Common AAVE/Compound Patterns ### Reserve Factor ```solidity // Protocol takes cut of interest uint256 interestToProtocol = interest * reserveFactor / 1e18; uint256 interestToSuppliers = interest - interestToProtocol; ``` ### Supply Index ```solidity // Track earnings per token // supplyIndex increases as interest accrues uint256 newIndex = oldIndex + (interest * 1e18 / totalSupply); // User earnings = balance * (currentIndex - userIndex) / 1e18 ``` --- ## Lending Audit Checklist ### Liquidation - [ ] Liquidation bonus < (100% - max LTV) - [ ] Bad debt handling exists - [ ] Partial liquidation supported - [ ] Liquidation can't be blocked (pausable tokens) - [ ] Self-liquidation not profitable ### Interest - [ ] Interest accrues correctly over time - [ ] No precision loss on small amounts - [ ] Rate manipulation resistance - [ ] Compound interest handled ### Collateral - [ ] Oracle is manipulation-resistant - [ ] Collateral factor changes have timelock - [ ] Collateral whitelist is reasonable - [ ] Handles rebasing/weird tokens properly ### Health Factor - [ ] Computed in real-time - [ ] Rounding favors protocol safety - [ ] Handles all edge cases (0 debt, 0 collateral) ### Access Control - [ ] Only authorized can change parameters - [ ] Emergency pause exists - [ ] Parameter bounds enforced ## Severity Classification ### Critical - Self-liquidation profitable - Bad debt not handled - Oracle manipulation allows draining ### High - Interest precision loss - Collateral factor instant changes - Same-block manipulation ### Medium - Missing borrow caps - Liquidation can be blocked - Rate model edge cases --- ## Rationalization Table | Root Cause | Historical Exploit | Detection Method | Severity | Mitigation | |-----------|-------------------|------------------|----------|-----------| | Health Factor Calculation Timing | Stale price liquidations (Aave v1 oracle failures) | Check if health factor computed real-time from oracle | Critical | Always compute health factor in real-time, validate oracle freshness | | Liquidation Incentive Misconfiguration | Self-liquidation profit (Compound liquidation bonus > safety margin) | Verify: bonus < (100% - max LTV) | Critical | Set liquidation bonus ≤ (100% - max LTV), audit parameter changes | | Interest Precision Loss | Dust attack exploits (small amounts accrue zero interest) | Check interest calculation for rounding to zero | High | Use high-precision accumulators (ray/wad), test with small amounts | | Collateral Valuation Trust | Oracle manipulation attacks (Euler oracle dependency) | Audit oracle source, check staleness, validate multi-source | Critical | Use manipulation-resistant oracles, implement staleness checks, multi-oracle fallback | | Bad Debt Socialization Gap | Protocol insolvency (Euler bad debt cascade) | Check if collateral < debt is handled | Critical | Implement bad debt handling, insurance fund, or liquidation guarantees |
عرض على GitHub