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

← Resource Hub

13 Liquidation Vulnerabilities Every DeFi Auditor Must Know

Updated 11 min read

Quick answer. Liquidation vulnerabilities stop a liquidation from happening on time or make it go wrong. Common ones are reverts from blacklisted or zero-amount transfers, insolvency and unpayable fees, plus missed fees, lost rewards and self-liquidation.

Almost every DeFi protocol has liquidation logic. That makes liquidation vulnerabilities some of the most valuable bugs to know.

This guide covers the basics first: what a liquidation is, and how an insolvent position differs from a liquidatable one. Then it walks through 13 liquidation edge cases, bugs and mishaps, in order.

It ends with an advanced attack on PnL-based protocols that can make for the best finding of a contest.

What Liquidation Is

Liquidation is the forced closing of a position. What a position means depends on the protocol. This guide uses two broad types.

Borrow and lending protocols

A position is the collateral a user supplies plus the tokens they borrow against it. The protocol must liquidate when the collateral's value no longer supports the borrow.

Protocols do not simply require collateral value to exceed borrow value. They multiply the collateral value by a loan-to-value (LTV) ratio below one, such as 0.80, set per collateral token.

Here is why. Say a user posts 30,000 USDC and may borrow $1 of bitcoin per $1 of USDC. They borrow $30,000 of bitcoin.

If USDC drops to $0.90, the protocol holds only $27,000 of collateral. The user walks away with the bitcoin, and the protocol takes a $3,000 loss.

With an LTV of 0.80, the user can only borrow up to 80% of the collateral's value. Once they breach that threshold, they can be liquidated.

The 20% gap is padding, so the protocol does not absorb that loss.

PnL-based protocols

Perpetuals and options protocols track a collateral amount plus a profit and loss (PnL) on the position, such as a long on a token.

When PnL goes negative, the losses come out of the collateral. The protocol liquidates when collateral plus PnL falls below a configured threshold.

Some protocols count positive PnL toward collateral and some do not. Negative PnL should always reduce it.

Insolvent vs Liquidatable

A position is insolvent when it does not have the assets to cover its debts or losses.

  • Borrow and lending: insolvent when collateral value, with no LTV applied, is below the borrowed value. Liquidatable when collateral value times the LTV is below the borrowed value.
  • PnL-based: liquidatable when collateral plus PnL falls below the threshold X. Insolvent when it falls below zero. With $10 of collateral and $15 of losses, the position is worth minus $5.

By this math, a position crosses the liquidatable line before the insolvent one. That is the whole point of the LTV ratio and the threshold.

Insolvency is always bad for a protocol. Every dollar of debt beyond the collateral's value is bad debt that will never be repaid, unless someone covers it as charity.

In a PnL-based protocol, the threshold should sit well above zero. Otherwise a price gap over a couple of blocks can take a position straight from healthy to insolvent.

An insolvent trader has gambled with free money. They took losses and only paid back part of them.

That is why liquidations must go through, and go through on time.

Many of the bugs below are ways to make them revert. A blocked liquidation leads to bad debt and losses the collateral cannot cover.

Token Transfer Reverts

1. Liquidation reverts due to blacklisted tokens

At the end of a liquidation, especially in perpetuals and options protocols, the contract usually closes the whole position. It then sends any remaining collateral back to the position's owner.

// End of decreasePosition, reached from liquidate()
collateralToken.safeTransfer(position.trader, outputAmount);

If the collateral is USDC, this is a problem. USDC's implementation contract inherits a blacklist.

Its transfer, transferFrom, approve and mint functions revert if the sender or the recipient is blacklisted.

A blacklisted trader therefore makes the liquidation revert. The only hurdle is getting collateral into the position.

One path is an account that is blacklisted after opening its position. That needs advance knowledge, perhaps because the attacker plans an exploit elsewhere. Unlikely, but conceivable.

The easier path exists in many complex perpetuals protocols: another address can provide collateral for an account.

The liquidation still sends the remainder to the blacklisted trader, so it still reverts.

2. Liquidation reverts due to zero transfers

Some ERC-20 tokens revert on a transfer of zero. The same line has a second issue: outputAmount is often zero during a liquidation.

Many tokens also revert on transfers to the zero address. We have not yet seen that cause a liquidation to revert, but it is worth checking.

Our weird ERC-20 tokens checklist covers both behaviors.

Fees in Liquidation

3. isLiquidatable does not account for fees

Whether the check lives in a view function or inside liquidate, it must update the fees the position owes.

Lending protocols accrue interest. PnL-based protocols often have borrowing fees and funding fees. Every fee should reduce the collateral, or the PnL, right in the liquidation check.

Getting this right is tricky. In a well-built check, such as an isPositionLiquidatable function, every new fee type adds special cases.

4. Liquidation should collect the latest fees

The liquidation itself must also collect the latest fees. If a liquidated position skips its interest, borrowing or funding fees, that is an issue.

Insolvency and Accounting Reverts

5. Liquidation reverts when a position becomes insolvent

Always examine the liquidation logic for what happens once a position is actually insolvent. Surprisingly often, it causes a revert or at least a miscount.

The most common result is a panic revert. The code subtracts the debt, or the losses, from the collateral, and the subtraction underflows.

// Bug: panics once loss > collateral
// uint256 remaining = collateral - loss;

// Handle the insolvent case explicitly:
uint256 remaining = loss >= collateral ? 0 : collateral - loss;

A well-built protocol has a special case that lets insolvent liquidations go through. On-time liquidations should make insolvency rare, but you still want to close the position.

Many protocols have no such case. You get a revert or wacky accounting, in lending protocols and PnL-based ones alike.

6. Liquidation reverts when a position cannot cover the fees

A liquidation usually involves at least two kinds of fees. There are normal protocol fees, such as interest, borrowing or funding. There is also the liquidator fee, which rewards whoever calls liquidate.

The collateral may be too small to cover them. That deserves the same special handling as an insolvent position.

A good pattern: if pending borrowing fees exceed the collateral, cover as much as possible, set the collateral to zero, and continue the liquidation.

If the liquidator fee is a percentage of the collateral left after protocol fees, it simply becomes zero instead of reverting.

But a zero fee brings back bug 2. If the token reverts on zero transfers, paying that fee reverts the liquidation.

These fee paths get hairy. That is why liquidations are among the best places to look for vulnerabilities.

7. Liquidation reverts due to accounting errors

More generally, any underflow or failed validation in the liquidation path blocks the liquidation. These are protocol specific, but they raise the chance of bad debt and protocol losses just the same.

Multi-Collateral Positions

8. Liquidations do not prioritize the lowest LTV asset

This applies to lending protocols where one position can hold several collateral tokens.

A position's borrowable amount is the value of each collateral times that collateral's LTV.

Say USDC has an LTV of 0.80, ether 0.60 and USDT 0.75. Then $1,000 of each is worth $800, $600 and $750 of borrowing power.

Now suppose ether falls, the position becomes liquidatable, and the protocol does a partial liquidation, as many do. Which collateral should go first?

Taking the lowest LTV, most volatile asset first raises the basket's average LTV, so the position's health improves.

Taking the higher LTV, more blue chip asset first does the opposite. Borrowing power drops in a stepwise fashion.

BasketUSDCETHUSDTWeighted LTV
Before liquidation$1,000$1,000$1,0000.717
After liquidating $500 of USDC$500$1,000$1,0000.700

Per dollar of collateral, the position can now borrow less. The liquidation can leave the position less healthy than before.

We reported exactly this in a real protocol, titled "Health score decreases after liquidation".

Because each token has a different LTV, liquidating one token changes borrowing power out of proportion to the change in liabilities.

9. Liquidations require too much gas

The same kind of multi-collateral protocol often loops over every collateral type during a liquidation. A CDP protocol's liquidate function might do exactly that.

If the loop grows to too many iterations, it can exceed the block gas limit. Then the liquidation can never happen, which is critical.

Incentives and User Outcomes

10. Liquidation does not prioritize the caller fee

The caller fee, or liquidator fee, is what makes liquidations happen. If the accounting does not pay it first, it can end up as zero, and so does the incentive to liquidate.

In the example from bug 6, the liquidation fee is zero whenever borrowing fees consume the collateral.

Even when it is not zero, it may be too small to be worth the gas.

Either way, liquidations will not happen on time. Positions go insolvent and the protocol carries bad debt. That is a valid finding.

11. Liquidations make users lose accumulated rewards

Many liquidations end by deleting the position entirely. If the position struct holds accumulated rewards, deleting it destroys them.

The user can no longer claim rewards they already earned through a separate claim function. Those rewards should not vanish because of the liquidation.

12. Users can force themselves to become liquidatable

If users can push their own position into liquidation, or drive its health down without limit, it is almost always a big issue.

They may avoid losses, then liquidate themselves and collect the liquidation reward. Often they can game the protocol outright.

We found this in an audit, in a finding titled "Swap margin used to game the AMM".

Users could sell options contracts to the AMM and collect the premium into their portfolio immediately.

They could then call the swap margin function repeatedly to pull value out, well past the point of insolvency, leaving no margin to cover losses.

The swap inside that function comes with slippage and fees, so the portfolio's value drops after each swap.

A health check was missing: nothing confirmed the position was still not liquidatable, let alone solvent.

Users could effectively sandwich themselves on purpose and drain the portfolio that backed their positions.

The Euler Finance exploit is a famous example. Users could donate their collateral to the protocol.

That let an attacker make their own position liquidatable and then liquidate it, profiting from the liquidator fee.

Combined with flash loans, it was exploited for hundreds of millions of dollars. Any path that lets a user make themselves liquidatable deserves a close look.

13. Positions in profit can still be liquidatable

This mainly applies to PnL-based protocols. Teams often assume a position in profit cannot be liquidated, since there are no losses to cover.

That is wrong. A position can have a tiny profit and large fees, enough to make it liquidatable.

Code that assumes otherwise can leave positions that go insolvent while profitable, yet cannot be closed.

Even when profitable liquidations are supported, walk through them.

The case is so unexpected that it often hides an accounting error, such as an underflow revert from bug 7. An attacker can engineer it on purpose.

Correct handling covers both signs of realized PnL. Without a branch for positive PnL, liquidated users would lose their profits, which is a serious issue too.

An Advanced Attack: The Unliquidatable Hedge

This attack works on PnL-based systems when you can stop a position from being liquidated until it is insolvent.

  1. Open a long and a short on the same token. If the price rises, the long profits. If it falls, the short profits.
  2. Find a knob that blocks liquidation until insolvency. Bug 1 is the classic one. If the trader is blacklisted for USDC and the protocol only pays out when outputAmount is above zero, the liquidation reverts until no collateral is left. A specific accounting error or zero transfers can work too.
  3. Wait for a price gap. Each position is capped at losing its collateral, but the opposite position's gains are not capped.

Say each position has $1,000 of collateral and the price gaps down. The long should have been liquidated earlier, but could not be.

By the time it is insolvent and liquidation goes through, its losses are $1,100. It can only pay the $1,000 it has.

In the same block, at the same price, the attacker closes the short with a $1,100 gain.

PositionCollateralPnL at liquidation priceRealized
Long (liquidated)$1,000-$1,100-$1,000
Short (closed)$1,000+$1,100+$1,100
Net+$100

Downside is capped and upside is not, whichever way the price moves. High leverage makes the strategy easiest to run and most profitable.

It is one of the most elegant attacks you can find, and it exists in any system where liquidation can be blocked until insolvency.

Liquidation Review Checklist

  • Can a blacklisted owner or a zero amount make the final transfer revert?
  • Does the liquidation check update every fee, and does the liquidation collect it?
  • Do insolvent positions and positions that cannot cover fees still liquidate cleanly?
  • Can any underflow or validation failure block the liquidation?
  • Does a partial liquidation take the lowest LTV collateral first?
  • Is gas bounded however many collateral types a position holds?
  • Is the liquidator fee paid first, and is it worth the gas?
  • Are accumulated rewards kept when a position is deleted?
  • Can a user make themselves liquidatable, through swaps, donations or anything else?
  • Are positions in profit handled, both in the check and in the payout?

How Guardian Helps

Guardian's smart contract audits build invariant suites around solvency, accounting and edge states, then send senior researchers after the protocol's economic assumptions.

With Vanguard, two independent teams review the same scope and cross-check each other's findings.

Frequently Asked Questions

What is the difference between insolvent and liquidatable?

Liquidatable means a position crossed the safety threshold, such as collateral times LTV falling below debt. Insolvent means its collateral cannot cover its debt or losses at all.

Why do liquidations need to go through on time?

A position not liquidated in time can become insolvent. Its collateral cannot cover its losses, and the protocol is left with bad debt.

How can a blacklisted token block a liquidation?

Liquidations often send leftover collateral to the position's owner. If the collateral is a token like USDC and the owner is blacklisted, that transfer reverts, and so does the liquidation.

Can a profitable position be liquidated?

Yes. A position with a small profit and large fees can still cross the liquidation threshold. Protocols that assume profitable positions are safe can leave them unclosable, or miscount them.

Sources

Stress-test your liquidations with Guardian

Guardian's invariant suites and researchers pressure-test solvency and liquidation paths before an attacker does.