Skip to content

FLO-6: withdrawAndPull() Can Leave Position Below minHealth Due to Deposit Rate Limiting #215

@liobrasil

Description

@liobrasil

Severity: Medium

Files Affected

  • cadence/contracts/FlowALPv1.cdc

Description

The withdrawAndPull() function allows users to withdraw funds while automatically pulling from a configured topUpSource if the withdrawal pushes the position below its minHealth. To process this top-up, the function calls _depositEffectsOnly() with the pulled funds. However, _depositEffectsOnly() enforces strict deposit rate limits (depositLimit() and userDepositLimitCap()). If the required top-up amount exceeds these limits, the excess funds are placed into the queuedDeposits mapping rather than being actively credited to the position's balance. At the end of the withdrawal execution, the contract only verifies that the postHealth is greater than or equal to 1.0 to prevent immediate liquidation, failing to assert that the health was actually restored to the required minHealth. This allows the transaction to succeed while leaving the position in a vulnerable, undercollateralized state. Exploit Scenario:

  • A user holds a position near its minHealth threshold and submits a transaction calling withdrawAndPull() to extract a portion of their collateral.
  • The contract calculates that the withdrawal will drop the position below minHealth and correctly pulls the required survival funds from the user's topUpSource.
  • The pulled funds are passed to _depositEffectsOnly(), but because the pool's current depositCapacity is low, the required top-up amount exceeds the immediate depositLimit().
  • The contract accepts a fraction of the top-up funds into the active balance and pushes the remainder into the asynchronous queuedDeposits dictionary.
  • Because the queued funds do not contribute to the position's immediate effective collateral, the position's health remains below minHealth.
  • The final sanity check only verifies that the health is strictly above 1.0 (liquidation threshold), allowing the transaction to complete and leaving the user's position dangerously undercollateralized and exposed to minor market fluctuations before the asynchronous queue processes.

Recommendation

Consider bypassing standard user-facing rate limits during internal systemic actions, such as automated top-ups and rebalancing deposits, to ensure the protocol's safety invariants are maintained instantly. Alternatively, tighten the post-withdrawal assertion to strictly require the position health to remain above minHealth unless it was already below it prior to the transaction.


Parent Issue: #209

Metadata

Metadata

Assignees

Labels

No labels
No labels

Type

No type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions