HardhatDeFi
15,000 USDC
View results
Submission Details
Severity: medium
Invalid

Denial-of-Service (DoS) Risk in Batch Functions Due to Unbounded Loops

Summary

The batchAddLiquidity function in AaveDIVAWrapper executes an unbounded loop over an externally provided array (_addLiquidityArgs). This design flaw allows an attacker or even a legitimate user to submit excessively large input arrays, leading to transactions exceeding the block gas limit, causing reverts, and effectively disrupting protocol operations.

Without safeguards like maximum array lengths, the function introduces a denial-of-service (DoS) vulnerability, preventing valid users from executing batch liquidity operations.


Vulnerable Code

function batchAddLiquidity(AddLiquidityArgs[] calldata _addLiquidityArgs) external override nonReentrant {
uint256 _length = _addLiquidityArgs.length;
for (uint256 i = 0; i < _length; i++) {
_addLiquidity(...);
}
}
​
  • _addLiquidityArgs.length is controlled entirely by the caller and not restricted.

  • The function iterates over the array without a cap, meaning a large array input could exceed block gas limits, making the function permanently uncallable in extreme cases.


Attack Scenarios

Scenario 1: Intentional DoS Attack by Overloading the Loop

Steps to Exploit

  1. An attacker calls batchAddLiquidity with an array containing thousands of liquidity requests.

  2. Due to unbounded iteration, the transaction consumes excessive gas.

  3. If the array is large enough, the block gas limit is exceeded, causing a revert.

  4. This results in DoS, preventing any other users from executing valid batch operations.

Outcome to protocol / users

  • Users cannot execute batch operations until the vulnerability is patched.

  • The attacker incurs minimal cost, as failing transactions only cost some gas, while the protocol and legitimate users suffer service disruptions.


Scenario 2: Accidental DoS by Large Valid Transactions

Not all cases require an attacker. Even legitimate users submitting large batch requests may unintentionally break the function.

Example

  • A whale user wants to deposit liquidity for hundreds of pools using batchAddLiquidity.

  • Since there’s no limit, the transaction becomes too expensive or exceeds the block gas limit.

  • Result: The transaction fails, wasting gas fees and making batch deposits impractical.


Impact

πŸ”΄ Severity: Maybe Medium because it doesn't lead to permanent DoS
βœ… Likelihood: High
βœ… Affected Parties: Protocol users, liquidity providers, and batch-processing functions

Consequences

  • Denial-of-Service (DoS): Large transactions prevent batch operations from executing successfully, disrupting protocol functionality.

  • High Gas Wastage: Users submitting large batch transactions may face failed transactions, leading to significant gas losses.

  • Protocol Inefficiency: Essential liquidity functions become unusable or unreliable, degrading user experience.


Proof of Concept (PoC)

Setup

The following PoC demonstrates how submitting a large batch array can disrupt the function, causing a DoS attack.

Malicious Contract Exploiting Unbounded Batch Processing

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.26;
​
interface IAaveDIVAWrapper {
function batchAddLiquidity(AddLiquidityArgs[] calldata _addLiquidityArgs) external;
}
​
contract DoSAttack {
IAaveDIVAWrapper public wrapper;
​
constructor(address _wrapper) {
wrapper = IAaveDIVAWrapper(_wrapper);
}
​
function exploitDoS() external {
AddLiquidityArgs; // Excessively large batch size
​
for (uint256 i = 0; i < 50000; i++) {
// Fill the array with dummy data
largeArray[i] = AddLiquidityArgs(...);
}
​
// This transaction will fail due to exceeding the block gas limit
wrapper.batchAddLiquidity(largeArray);
}
}
​

  1. If batch limits are not enforced, the transaction will consume excessive gas and revert.

  2. Repeated large batch submissions can effectively block valid transactions.

  3. Legitimate users suffer collateral damage, facing high gas costs and service disruptions.


Fixes

Fix 1: Enforce a Hard Limit on Batch Sizes

Introduce a Maximum Array Length

Restrict the batch size to a reasonable limit (e.g., MAX_BATCH_SIZE = 100) to prevent DoS.

uint256 constant MAX_BATCH_SIZE = 100;
​
function batchAddLiquidity(AddLiquidityArgs[] calldata _addLiquidityArgs) external override nonReentrant {
require(_addLiquidityArgs.length <= MAX_BATCH_SIZE, "Batch size exceeds limit");
​
uint256 _length = _addLiquidityArgs.length;
for (uint256 i = 0; i < _length; i++) {
_addLiquidity(...);
}
}
​

βœ… Prevents excessively large inputs that could exceed gas limits
βœ… Maintains protocol efficiency without blocking valid transactions
βœ… Protects against DoS without limiting normal batch functionality


Fix 2: Implement Gas-Optimized Processing

Updates

Lead Judging Commences

bube Lead Judge 10 months ago
Submission Judgement Published
Invalidated
Reason: Known issue

Support

FAQs

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

Give us feedback!