Skip to content
$1,000,000 in security audit grants are live now, Apply here →

Security review · September 2026

Iris Protocol

for iris.credit

Guardian's review of Iris Protocol for iris.credit, published September 2026. The report records 11 findings across 2 review rounds, including 6 medium and 3 low.

Published
Review window
August 27 to September 25, 2026
Rounds
Main Review, Remediation Review
Language
Solidity
Chains
Ethereum
Sector
Lending
  • 0 Critical
  • 0 High
  • 6 Medium
  • 3 Low
  • 2 Informational

5 resolved · 6 acknowledged

Scope

11 files in scope · 953 nSLOC
FilenSLOCLines
src/adapters/AaveV3Adapter.sol7098
src/adapters/MorphoBlueAdapter.sol92138
src/blm/Blm.sol2846
src/blm/WhitelistBlm.sol3554
src/interfaces/IBlm.sol917
src/interfaces/IIris.sol8695
src/interfaces/IPod.sol58
src/interfaces/IVenueAdapter.sol610
src/interfaces/IWhitelistBlm.sol511
src/Iris.sol592921
src/Pod.sol2535

Findings 11

Main Review

9 findings
  1. M-01 Medium Liquidation Charges Fixed and Floating Business logic errors Resolved
    Location
    src/Iris.sol:439-484, 813-832, 890-905
    Round
    Main Review

    Description

    Iris promises borrowers a fixed-rate obligation: the borrower should pay principal plus fixed interest, while the solver bond absorbs venue floating interest above that fixed amount.

    That accounting breaks after a venue liquidation. When a liquidator repays venue debt using seized borrower collateral, the repayment can include accrued floating interest. _rebase() then reads only the remaining venue debt and clamps or removes the floating leg that was already paid through the liquidation. The paid floating cost is treated as if it never existed, so it is no longer charged against the solver bond.

    Root Cause

    _rebase() derives the position's floating exposure from the live venue debt after liquidation. It does not separately track realized venue funding costs that were already paid by borrower collateral. As a result, when venue debt is reduced or fully repaid by liquidation, _rebase() can reduce floatingLeg to the remaining debt and erase the portion of floating interest that was economically funded by the borrower through seized collateral.

    Example

    Consider a position at maturity with:

    • 100 principal
    • 10 floating interest
    • 5 fixed interest
    • collateral worth 121 debt tokens
    • enough solver bond to cover the 5 negative spread

    In an 86% LLTV Morpho market, the position is liquidatable. A liquidator can repay the full 110 venue debt, seize about 114.82 of collateral including the venue liquidation bonus, and leave about 6.18 collateral in the Pod. M-01 Liquidation Charges Fixed and Floating C O N T I N U E D

    After _rebase() , Iris records zero principal and zero floating interest while preserving the 5 fixed-interest claim. The solver bond remains untouched. Because collateral remains, the borrower must still pay 5 through repay() before calling escape() . Ignoring the venue's ordinary liquidation bonus, the borrower funded 110 through seized collateral and another 5 through Iris. The borrower pays 115 despite the promised fixed obligation being 105 . The erased 10 floating interest is shifted away from the solver bond.

    Impact

    The borrower can overpay relative to the fixed-rate obligation, while the solver and fee recipient can still receive the fixed settlement and the solver can recover an unslashed bond. This contradicts the fixed-rate design, where solver backing is supposed to absorb venue floating costs above the borrower's fixed obligation.

    Recommendation

    Track realized venue funding costs separately from outstanding venue debt. When liquidation uses borrower collateral to retire floating interest, preserve that realized floating cost for settlement instead of deleting it during _rebase()

    Resolution

  2. M-02 Medium Delayed Rebase Falsely Slashes Solver Bond Business logic errors Acknowledged
    Location
    src/Iris.sol:653-656, 691-698, 813-830, 849-887
    Round
    Main Review

    Description

    Iris calls _accrueLegs() before _rebase() when updating a position. If Morpho partially liquidates a Pod between Iris calls, Iris calculates interest using the old debt before reading the reduced Morpho debt. Debt already repaid through the Morpho liquidation is therefore treated as outstanding until Iris is updated. When the floating rate exceeds the fixed rate, this creates excess negative spread and can make a healthy solver bond liquidatable.

    The Iris borrower can profit because Morpho recognizes the Pod, rather than the Iris borrower, as its borrower and allows arbitrary callers to perform partial liquidations. The borrower can liquidate the Pod, wait without another Iris update, call liquidateBond() with a controlled receiver, and then call escape(). Calling rebase() promptly prevents this, but no onchain deadline or protocol-enforced keeper guarantees that it will be called when the Morpho liquidation happens.

    Consider 10,000 USDC principal, a solver-selected 305.67 USDC bond, 90% bond LLTV, a 5% annual fixed rate, and a high-utilization 86% LLTV Morpho market. The bond is ten times the current public BLM minimum of 30.567 USDC: 10,000 × (30 × 0.00010184 + 0.0000015) = 30.567 . Iris allows the solver to post any bond at or above this minimum.

    At 26 days, 8 hours, and 4 minutes into the 30-day loan, Iris is updated immediately before the Morpho liquidation. Negative net is 273.224847 USDC, below the 275.103000 USDC bond boundary. A price move makes the Pod liquidatable, and the borrower liquidates 90% of its borrow shares. The remaining Morpho position is healthy at approximately 53.84% LTV. If rebase() is called immediately after the Morpho liquidation, negative net two hours later is 273.417762 USDC and the bond remains healthy. If rebase() is not called during those two hours, Iris instead records 275.122214 USDC when liquidateBond() is called and allows the bond liquidation.

    The correct path leaves 32.606187 USDC of solver bond. The delayed path leaves only 15.264286 USDC, pays the borrower a 15.283500 USDC bounty, and reduces the borrower’s closing cost by 17.341901 USDC. This equals the additional solver bond consumed. If Iris had been M-02 Delayed Rebase Falsely Slashes Solver Bond C O N T I N U E D

    updated immediately, the bond would not become liquidatable until 18 hours, 57 minutes, and 18 seconds after the Morpho liquidation. The bug therefore makes it liquidatable 16 hours, 57 minutes, and 18 seconds early.

    Recommendation

    Prevent a delayed rebase from increasing the amount taken from the solver’s bond. When _rebase() detects that Morpho liquidated part of the position, Iris should not charge the solver as though the repaid debt remained outstanding until the rebase call.Since Morpho’s current balance does not show when the liquidation happened, affected positions should be handled separately instead of estimating the missing interest.

    Resolution

    iris.credit Team: Acknowledged with an additional comment followed by the remediation (PR) link

  3. M-03 Medium _accrueLegsView() over-accrues surplus on pre- liquidation Aave collateral and _rebase() converts the overage into solver owned yield Business logic errors Acknowledged
    Location
    —
    Round
    Main Review

    Description

    _accrueLegsView() com putes surplus from stalestored(pos.collateral + pos.surplus) b eforelive
    

    venue collateral is synced. _accrueLegs() persists that inflated amount. Then _rebase() uses the inflated total in liquidated = (pos.collateral + pos.surplus) - venueCollateral , while only clamping surplus if venueCollateral <= pos.surplus . That keeps pos.collateral + pos.surplus equal to the live venue balance, but the split is wrong after a partial Aave liquidation: yield is accrued on collateral that was already seized. The excess is paid out later as solver surplus , and the borrower’s remaining principal collateral is reduced instead.

    Example: 1. Borrower opens an Aave-backed loan with collateral = 100 , surplus = 0 . 2. Aave partially liquidates 40 collateral / 30 debt, leaving 60 live collateral. 3. Before the first Iris sync, Aave income grows 20% , so live collateral becomes 72 . 4. Any later path starting with _accrueLegs() books 20 surplus from the stale 100 base; _rebase() then reduces principal to 52 . 5. On close, the solver receives 20 collateral as surplus and the borrower can only escape 52 . 6. Correct accounting was solver 12 , borrower 60 ; 8 borrower collateral is silently reassigned.

    This issue is Aave specific; Morpho collateral does not accrue via a collateral index

    Recommendation

    When a liquidation is being rebased, recompute surplus from live venueCollateral instead of preserving the pre-rebase accrual, or subtract the accrued yield attributable to the liquidated collateral slice before storing pos.surplus M- _accrueLegsView() over-accrues surplus on pre-liquidation Aave collateral C O N T I N U E D 03 and _rebase() converts the overage into solver owned yield

    Resolution

    iris.credit Team: Acknowledged with an additional comment followed by the remediation (PR) link

    https://github.com/iris-credit/iris-core/pull/21

  4. M-04 Medium setAuthorizationWithSig() lets stale signed grants restore revoked operators Signatures Resolved
    Location
    —
    Round
    Main Review

    Description

    setAuthorizationWithSig() only checks whether a nonce has never been used, then writes the signed boolean directly. A signer who later revokes an operator with setAuthorization() or a newer signed revoke does not invalidate older unused isAuthorized=true signatures, so the former operator can replay the stale grant and regain access. From there it can use the normal auth-gated sinks in withdrawBond() , claim() , withdrawCollateral() , or escape() to redirect assets to itself

    Recommendation

    Use a monotonic per-authorizer authorization version and advance it on every direct authorization change, so a later revoke invalidates all older signed grants.

    Resolution

  5. M-05 Medium Borrowers can flash-wash tracked collateral to steal solver Aave yield accounting bypass Resolved
    Location
    packages/onchain-ethereum-type4/src/__onchain/poolinstance-728a138a4823392c/src/
    Round
    Main Review

    Description

    Aave permits anyone to supply collateral on behalf of a Pod. Iris ignores excess live Aave collateral above its tracked Position.collateral .

    An overcollateralized borrower can supply collateral directly to Aave for the Pod, then withdraw the same amount through Iris.withdrawCollateral() . The direct supply temporarily raises the live venue balance, allowing the Iris withdrawal to return the supplied tokens. The Pod's actual Aave collateral remains unchanged, but Iris decreases pos.collateral . Future Aave collateral-index growth on the washed amount is no longer booked as Position.surplus , so the borrower can later recover that hidden yield through escape() instead of paying it to the solver and fee recipient.

    Root Cause

    withdrawCollateral() and _rebase() do not reconcile or classify direct Aave collateral donations before reducing tracked collateral.

    When live collateral exceeds Iris accounting:

    • _rebase() ignores the upward discrepancy.
    • withdrawCollateral() allows the borrower to withdraw tokens.
    • Iris decrements pos.collateral .
    • the raw Aave aToken balance can remain economically unchanged.

    This lets the borrower reduce the accounting base used by _accrueLegsView() to compute solver-owned surplus, without reducing venue safety or committing lasting capital.

    Attack Path
    1. The borrower opens an Aave-backed Iris position with excess collateral.
    2. The borrower supplies D collateral directly to Aave on behalf of the Pod.
    3. The Pod's live Aave collateral increases by D , but Iris does not attribute that increase to
    pos.collateral .
    

    M-05 Borrowers can flash-wash tracked collateral to steal solver Aave yield C O N T I N U E D

    1. The borrower calls withdrawCollateral(D) through Iris.
    2. Aave returns D , leaving the Pod's live venue collateral effectively unchanged from the pre-attack state.
    3. Iris still reduces pos.collateral by D .
    4. Over time, the full live Aave collateral balance earns yield, but Iris computes surplus only on the reduced

    tracked base. 8. On repayment and escape() , the borrower receives the yield earned by the untracked collateral base.

    Impact

    The borrower can divert collateral yield that the fixed-rate quote economics allocate to the solver and fee recipient. The attack can be capital-neutral with flash liquidity, does not reduce venue health, and scales with the washed collateral amount, venue APY, loan term, and number of positions

    Recommendation

    Reconcile/classify live collateral donations before tracked withdrawals, e.g. checkpoint scaled aToken shares and separate principal/donation buckets, or cap withdrawal accounting by the actual Pod live-balance decrease. Accrue surplus from economically attributed live collateral rather than nominal Position.collateral after donation-assisted withdrawal.

    Before permitting a tracked withdrawal, reconcile live Aave collateral above Iris accounting

    Resolution

  6. L-01 Low Off-ledger venue repay can stale Iris debt and let the borrower extract the solver bond Business logic errors Acknowledged
    Location
    —
    Round
    Main Review

    Description

    Summary

    Iris can keep pos.debt materially higher than the real debt owed on the underlying venue.

    This happens when venue debt is reduced outside of Iris, either through direct repayment or through a venue liquidation whose collateral loss is hidden or understated. In those cases, _rebase() does not fully reconcile the lower live venue debt into Iris storage. The stale pos.debt then continues accruing floating interest through _accrueLegsView() . Later, liquidateBond() can treat the position as unhealthy based on the inflated internal debt, while resolving the venue side against the smaller live debt reported by the adapter. This can let the borrower slash the solver bond and potentially receive an unjustified liquidation incentive. Afterward, the borrower can call escape() and recover the remaining collateral by paying only the smaller live venue debt.

    Root Cause

    _rebase() compares Iris accounting against live venue balances, but it only reconciles debt reductions when they are associated with visible collateral loss. If live venue debt falls while collateral remains unchanged, _rebase() returns early and leaves pos.debt stale. If collateral loss is visible but understated, _rebase() only credits debt reduction up to the value of that collateral delta. This can also leave pos.debt above the true venue debt.

    This affects both Morpho and Aave: L- Off-ledger venue repay can stale Iris debt and let the borrower extract C O N T I N U E D 01 the solver bond

    • - Morpho allows a borrower to directly call repay(onBehalf = pod) , reducing venue debt while leaving

    venue collateral unchanged.

    • - Aave also allows direct repayment on behalf of the Pod.
    • - Aave entry/refinance flows can introduce small collateral rounding mismatches. When this happens,

    _rebase() may interpret the external repay as a tiny liquidation and only credit a tiny debt reduction, leaving most repaid debt stale.

    Attack Path
    1. 1. The borrower opens an Iris position and receives the borrowed debt tokens.
    2. 2. The borrower uses those tokens to repay the underlying venue directly on behalf of the Pod.
    3. 3. The venue debt decreases, but Iris does not fully sync the repayment.
    4. 4. pos.debt remains materially overstated.
    5. 5. Floating interest continues accruing on the stale internal debt.
    6. 6. The position eventually appears to create a solver bond shortfall.
    7. 7. The borrower calls liquidateBond() .
    8. 8. liquidateBond() slashes the solver bond and may pay the borrower a liquidation incentive.
    9. 9. The borrower calls escape() and recovers the remaining collateral by paying only the residual live venue

    debt.

    Impact
    • - Solver bond value can be consumed by debt that no longer exists on the venue.
    • - The borrower can receive an unjustified liquidation reward.
    • - The borrower can close the position more cheaply than the fixed-rate trade intended.
    • - Iris accounting can diverge materially from the underlying venue state.
    Variants
    1. Morpho direct repayment

    The borrower directly repays Morpho debt with repay(onBehalf = pod) . Venue debt decreases, collateral remains unchanged, and _rebase() returns before reducing pos.debt . The stale internal debt then accrues floating interest and can later be used to slash the solver bond.

    2. Aave direct repayment with rounding mismatch

    The borrower directly repays Aave debt on behalf of the Pod.

    If Iris’s expected collateral balance differs slightly from the live Aave balance due to entry or refinance rounding, _rebase() may treat the mismatch as a small liquidation. It L- Off-ledger venue repay can stale Iris debt and let the borrower extract C O N T I N U E D 01 the solver bond

    then credits debt reduction only up to the value of that tiny collateral delta, leaving most of the externally repaid debt in pos.debt .

    3. Morpho liquidation with collateral returned to the Pod

    The same issue can occur through an actual Morpho liquidation.

    A liquidator can reduce the Pod’s Morpho debt and return the seized collateral to the Pod during the liquidation callback. From Iris’s perspective, collateral appears unchanged while debt is lower. _rebase() therefore skips the debt reduction and leaves stale pos.debt .

    4. Partial venue liquidation followed by price movement

    A partial venue liquidation can reduce both collateral and debt. If the oracle price drops before _rebase() runs, the computed value of the collateral loss is lower. As a result, _rebase() syncs the collateral loss but only credits debt reduction up to the later, lower value of the collateral delta. This can leave pos.debt above the live Morpho debt. The phantom principal then accrues floating interest and can later be used to slash the solver bond.

    5. Morpho full-debt liquidation masked by collateral resupply

    If a loan is opened at or near LLTV, a small interest tick can make the Pod externally liquidatable even though Iris still records the original principal.

    The borrower, or a cooperating liquidator, can liquidate all Morpho borrow shares and then resupply the seized collateral to the Pod. Live venue debt becomes zero, while live collateral again matches Iris’s stored collateral expectation. Because _rebase() sees no collateral shortfall, it skips the debt reduction. Iris keeps phantom principal in pos.debt , which continues accruing floating interest until liquidateBond() can slash the solver bond.

    6. Aave full-wipe masking variant

    After Aave wipes a Pod to zero collateral and zero debt, the borrower can directly resupply collateral on behalf of the Pod up to Iris’s stale expected collateral balance. Because AaveV3Adapter reports the raw aToken balance, _rebase() sees no collateral shortfall and returns before reconciling the zero live debt. This preserves stale debt, floating loss, and the inflated bond requirement. The borrower can then call liquidateBond() against the stale negative net position, collect the bond incentive, and later recover the injected collateral through escape() L- Off-ledger venue repay can stale Iris debt and let the borrower extract C O N T I N U E D 01 the solver bond

    Recommendation

    Make _rebase() fully reconcile external venue debt reductions, even when there is no collateral loss

    Resolution

    iris.credit Team: Acknowledged, severity disputed to Low. Direct venue repays are documented as out of scope and left unreconciled (Iris.sol header 100-102, 116-118). The bond liquidation path only opens if the variable rate stays above the fixed rate long enough for the stale debt to eat through the bond, which the borrower cannot control, and the direct repayment is lost if it does not.

  7. L-02 Low Liquidations Lack Execution Bounds liquidation economics / MEV Resolved
    Location
    packages/iris-core/src/Iris.sol:withdrawCollateral():L571-L605
    Round
    Main Review

    Description

    Iris’s liquidate() function provides no maximum repayment, minimum collateral output, or deadline. An authorized borrower can therefore front run a pending overdue liquidation and materially worsen its execution without making it revert. After maturity + overduePeriod , withdrawCollateral() reserves tracked collateral only against principal and accrued fixed obligations. It excludes badBond and the liquidation incentive. On Aave, accrued collateral yield is recorded as surplus belonging to the solver. This surplus supports venue health but is unavailable to the liquidator. The borrower can therefore withdraw tracked principal to Iris’s LLTV boundary while the venue remains healthy. The pending liquidation still charges pos.debt + pos.fixedLeg + badBond , but collateral output is silently capped at the reduced pos.collateral . A transaction that was profitable when submitted can execute at a principal loss. The borrower keeps the withdrawn collateral while the solver retains the surplus.

    The loss results from borrower controlled state changes between transaction submission and execution, rather than from a liquidator knowingly accepting an unprofitable position. Because liquidate() has no caller supplied execution bounds, the transaction proceeds under materially worse terms instead of reverting.

    Recommendation

    Add maxRepaid, minSeized, and deadline parameters to liquidate(). Validate them after accrual and rebase but before pulling funds from the liquidator. Optionally disable collateral withdrawals after liquidation eligibility or reserve collateral against the complete liquidation exposure.

    Resolution

  8. L-03 Low Self-Liquidation Erases Future Fixed Interest state synchronization Acknowledged
    Location
    packages/iris-core/src/Iris.sol:439-485, 813-830, 890-899
    Round
    Main Review

    Description

    Iris.repay accrues, rebases a two-sided venue liquidation, then settles the fixed overlay. _rebase subtracts venue-repaid principal from pos.debt; _settleLegs computes residual fixed interest through maturity only on the reduced debt. A borrower-controlled address can trigger permissionless Morpho liquidation while the overlay remains live, then repay Iris and bypass the fixed obligation on the liquidated principal.

    Impact: The borrower group can capture the liquidation proceeds while avoiding the remaining fixed interest on the retired principal. The correct economic comparison uses actual debt-token debits: the normal Iris repayment versus the Morpho liquidation payment plus the attacked Iris repayment, with external fees and gas included. In the prompt early-liquidation witness, accrued floating interest is negligible, so the normal payment exceeds the attacked path by almost the remaining fixed face. The solver loses the corresponding contracted return, and the protocol loses its performance fee on that return.

    Recommendation

    Preserve the fixed-term obligation on principal recognized as repaid by an underlying venue liquidation: track venue-repaid principal separately or add residual fixed interest through maturity before reducing pos.debt. Add partial/full Aave and Morpho liquidation-then-repay tests to ensure fixed charges are invariant to venue liquidation ordering.

    Resolution

    iris.credit Team: Acknowledged, severity disputed to Low. The fixed residual is reserved in withdrawCollateral, so a borrower cannot reach the venue liquidation threshold without an exogenous price move of at least the residual, not atomically exploitable.

  9. I-01 Informational First Aave Borrow Can Desync Debt Index Business logic errors Acknowledged
    Location
    packages/iris-core/src/Iris.sol:400-431; packages/iris-core/src/adapters/AaveV3A
    Round
    Main Review

    Description

    Iris snapshots Aave's normalized variable-debt index before entering the venue. If a reserve has zero scaled variable debt, a positive stored currentVariableBorrowRate, and a meaningful idle interval, Aave's view function projects an index above the stored index. This state can occur when the reserve has a nonzero configured base variable rate.

    During the first subsequent borrow, Aave does not persist the projected index because scaled variable debt is still zero when the reserve indexes are updated. The Pod's debt is therefore minted using the lower stored index, while Iris has already recorded the higher projected index.

    Iris consequently stores a debt-index baseline above the index used to mint the Pod's debt. Accrue-first actions revert until the live index catches up. After catch-up, Iris omits the intervening venue interest even though repay() must still fund the full live Aave debt. In an affected configuration, the difference could be drawn from pooled assets backing unrelated bonds or claims.

    This is a latent configuration risk, not a currently executable production loss. The deployed Iris BLMs admit USDC, USDT, and WETH debt. Their Aave reserves have nonzero aggregate debt and reset to a zero base rate if debt reaches zero, preventing the required idle-index projection.

    The PoC uses tBTC and a configured dormant-reserve state to demonstrate the underlying index behavior. That configuration cannot currently be originated through deployed Iris. The condition would become relevant only if Iris later admits an Aave reserve with zero scaled variable debt and a positive stored currentVariableBorrowRate.

    Recommendation

    No immediate remediation is required for the currently supported markets. Reassess this condition before admitting any additional Aave debt asset, particularly a reserve with zero scaled variable debt and a positive stored currentVariableBorrowRate. I-01 First Aave Borrow Can Desync Debt Index C O N T I N U E D

    Resolution

    iris.credit Team: Acknowledged with an additional comment followed by the remediation (PR) link

    https://github.com/iris-credit/iris-core/pull/24

Remediation Review

2 findings
  1. M-01 Medium Post-wipe collateral supply makes the solver bond claimable by the borrower Business logic errors Resolved
    Location
    src/Iris.sol:840-885
    Round
    Remediation Review

    Description

    The M-01 fix added logic to _rebase() that refunds the borrower when collateral sold during a venue liquidation repays more than the recorded principal and fixed interest. Fully wiped positions are excluded from this refund, but Iris recognizes a wipe only when the venue’s current collateral and debt balances are both exactly zero.

    Following a complete Morpho liquidation, any liquidator can resupply one unit of the seized collateral on behalf of the Pod. Iris consequently observes positive collateral and zero debt. This prevents the wipe from being recognized while leaving bondRequirement active. When rebase is called, Iris accounts for the liquidated collateral as repayment, settles the fixed leg, and credits any remaining excess from the solver bond to the borrower. Without the additional collateral, the same liquidation resolves the position without creating a borrower refund. Any liquidator can supply the collateral and call rebase during Morpho’s liquidation callback, forcing the bond transfer without authorization from the borrower or solver. The resulting claim belongs to the borrower. If the liquidator is controlled or authorized by the borrower, it can also claim the refund during the callback and use it toward the repayment Morpho collects afterward.

    Depending on the liquidated collateral value and accumulated floating interest, the borrower can receive up to the position’s full remaining bond. The loss is limited to each affected position but can occur independently across multiple loans.

    Recommendation

    Ensure that collateral supplied after a terminal venue liquidation cannot change how Iris resolves the position or make the solver bond refundable. M- Post-wipe collateral supply makes the solver bond claimable by the C O N T I N U E D 01 borrower

    Resolution

  2. I-01 Informational Resolved loans permanently lose partial collateral withdrawals after the original deadline Business logic errors Acknowledged
    Location
    src/Iris.sol:613, withdrawCollateral(), liquidateBond(), escape()
    Round
    Remediation Review

    Description

    While the loan is active, the borrower may withdraw part of the collateral.

    The code permits partial withdrawals only until the loan's deadline (maturity plus grace). After that deadline, an unresolved loan can be liquidated, so allowing collateral withdrawals could let the borrower strip value before liquidation.

    However, a loan can also become resolved. Bond liquidation ends the solver's side, zeroes the borrower's Iris debt and interest, and leaves the borrower with the underlying venue position at a variable rate. In that resolved state, Iris's liquidate(), liquidateBond(), repay(), and rebase() revert. The underlying venue debt can still exist and remains subject to the venue's own rules.

    The bug is that withdrawCollateral() still applies the original fixed-loan deadline check at line 613 without checking whether the loan is resolved.

    Once that deadline passes, even a healthy resolved position can never make a partial collateral withdrawal again, although the fixed-rate Iris obligation has ended and Iris liquidation is no longer possible.

    The only remaining route is escape(), which requires funding the entire live venue debt and closes the whole position. Recovery is therefore all or nothing.

    Impact: The borrower loses the ability to manage the continuing venue position through partial withdrawals and must fully repay and exit to recover any collateral. This is a persistent functional restriction caused by applying a guard against Iris liquidation to a state in which that liquidation cannot occur.

    Reproduction

    1. Open a loan and resolve it through bond liquidation while a healthy collateralized venue position remains

    I- Resolved loans permanently lose partial collateral withdrawals after the C O N T I N U E D 01 original deadline

    1. Advance beyond the original maturity-plus-grace deadline
    2. Attempt an otherwise valid partial collateral withdrawal
    3. Observe that the deadline check reverts despite resolution; recovering collateral through escape() requires

    fully repaying the live venue debt and exiting

    Summary

    collateral withdrawals retain the fixed-loan deadline after resolution into a variable-rate position

    Healthy borrowers can lose partial-withdrawal access and need full debt repayment to exit

    Recommendation

    Apply the maturity-plus-grace withdrawal deadline only to unresolved loans. Preserve borrower authorization and the existing collateral and venue health constraints for withdrawals from resolved positions.

    Resolution

    iris.credit Team: https://github.com/iris-credit/iris-core/commit/b13a527dff9d6c5b0a25357377841e9f9b152c6a

    just add comments.

    Deadline represents the period during which Iris manages the loan. Therefore, after the deadline, the borrower is expected to exit through escape().

Put your code through the same review.

This review started with a conversation about scope. Tell us what you are building and we will plan yours with you.

Get a quote