Part 2

Zaros
PerpetualsDEXFoundrySolidity
70,000 USDC
View results
Submission Details
Severity: medium
Invalid

Dust Withdrawal DoS Attack Through Credit Capacity Saturation in Withdrawal Mechanism

Description

The protocol's redemption mechanism can be effectively denied to legitimate users through a low-cost dust withdrawal attack, potentially trapping user funds in the protocol.

The initiateWithdrawal function lacks a minimum withdrawal threshold, enabling an attacker to execute a denial-of-service attack against the protocol's credit capacity system, preventing legitimate withdrawals.

function initiateWithdrawal(uint128 vaultId, uint128 shares) external {
if (shares == 0) {
revert Errors.ZeroInput("sharesAmount");
}
// ... rest of function
}

The attack exploits the protocol's credit capacity system through a continuous cycle of dust-sized withdrawal requests. By flooding the protocol with minimal withdrawal requests, the attacker consumes protocol credit capacity in small increments, then maintains this pressure by creating new requests as old ones expire. This creates a sustained drain on the system's credit capacity with minimal cost to the attacker, effectively weaponizing the withdrawal mechanism against the protocol itself.

The crucial vulnerability lies in the redeem check:

if (
ctx.creditCapacityBeforeRedeemUsdX18.sub(vault.getTotalCreditCapacityUsd()).lte(
ctx.lockedCreditCapacityBeforeRedeemUsdX18.intoSD59x18()
)
) {
revert Errors.NotEnoughUnlockedCreditCapacity();
}

Proof of Concept

// Attack contract
contract WithdrawalAttack {
function attack(address vault, uint128 vaultId) external {
for (uint i = 0; i < 1000; i++) {
VaultRouter(vault).initiateWithdrawal(vaultId, 1);
}
}
}

Impact

The attack creates a cascading effect on protocol functionality by saturating credit capacity with dust withdrawals, effectively preventing legitimate users from executing larger withdrawals. This leads to a situation where user funds become temporarily locked in the protocol, while the system suffers from mounting gas costs due to the processing overhead of backlogged withdrawal requests. The situation is particularly severe because the attacker can continuously cycle through this process, maintaining a persistent denial of service condition that disrupts normal protocol operations and undermines user confidence in the withdrawal mechanism.

Recommended Fix

function initiateWithdrawal(uint128 vaultId, uint128 shares) external {
if (shares < MINIMUM_WITHDRAWAL_SHARES) {
revert WithdrawalTooSmall(shares, MINIMUM_WITHDRAWAL_SHARES);
}
// Add cumulative withdrawal tracking
uint256 totalPendingWithdrawals = getUserPendingWithdrawals(msg.sender);
if (totalPendingWithdrawals + shares > MAX_PENDING_WITHDRAWAL_PER_USER) {
revert ExcessivePendingWithdrawals();
}
// ... rest of function
}
Updates

Lead Judging Commences

inallhonesty Lead Judge
6 months ago
inallhonesty Lead Judge 6 months ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.