HardhatFoundry
30,000 USDC
View results
Submission Details
Severity: low
Invalid

Use of Loops in Public or External Functions Potentially Causing a DoS Attack

File location:

Summary

Using loops in public or external functions in Solidity can lead to high gas costs and potential Denial of Service (DoS) attacks. A DoS attack can occur when an attacker intentionally exploits the gas costs of a function, causing it to run out of gas or making it too expensive for other users to call.

Vulnerability Details

Loops in public or external functions can process large amounts of data in a single transaction, leading to very high gas fees. If the loop is not properly constrained, an attacker can send very large amounts of data to force the function to run out of gas, making it unusable by other users. Additionally, nested loops or double loops can exacerbate this problem.

Impact

  • The function becomes inaccessible to other users due to running out of gas.

  • Gas costs are very high, making the function uneconomical to use.

  • Damage or disruption to smart contract services that depend on such functionality.

Tools Used

  • Inspection manual

  • Solidity

  • Foundry

Recommendations

Limit the input size. Make sure the size of the array received by the function is not too large. This can be done by limiting the input length on the frontend side or by checking the array length in the contract.

Code snippet:

L55-L87

function initNexus(
BootstrapConfig[] calldata validators,
BootstrapConfig[] calldata executors,
BootstrapConfig calldata hook,
BootstrapConfig[] calldata fallbacks,
IERC7484 registry,
address[] calldata attesters,
uint8 threshold
) external {
// Initialize validators
for (uint256 i = 0; i < validators.length; i++) {
_installValidator(validators[i].module, validators[i].data);
}
// Initialize executors
for (uint256 i = 0; i < executors.length; i++) {
if (executors[i].module == address(0)) continue;
_installExecutor(executors[i].module, executors[i].data);
}
// Initialize hook
if (hook.module != address(0)) {
_installHook(hook.module, hook.data);
}
// Initialize fallback handlers
for (uint256 i = 0; i < fallbacks.length; i++) {
if (fallbacks[i].module == address(0)) continue;
_installFallbackHandler(fallbacks[i].module, fallbacks[i].data);
}
_configureRegistry(registry, attesters, threshold);
}

L93-L111

function initNexusScoped(
BootstrapConfig[] calldata validators,
BootstrapConfig calldata hook,
IERC7484 registry,
address[] calldata attesters,
uint8 threshold
) external {
// Initialize validators
for (uint256 i = 0; i < validators.length; i++) {
_installValidator(validators[i].module, validators[i].data);
}
// Initialize hook
if (hook.module != address(0)) {
_installHook(hook.module, hook.data);
}
_configureRegistry(registry, attesters, threshold);
}

Fixed code:

uint256 constant MAX_ARRAY_LENGTH = 50;
function initNexus(
BootstrapConfig[] calldata validators,
BootstrapConfig[] calldata executors,
BootstrapConfig calldata hook,
BootstrapConfig[] calldata fallbacks,
IERC7484 registry,
address[] calldata attesters,
uint8 threshold
) external {
require(validators.length <= MAX_ARRAY_LENGTH, "Validators array too long");
require(executors.length <= MAX_ARRAY_LENGTH, "Executors array too long");
require(fallbacks.length <= MAX_ARRAY_LENGTH, "Fallbacks array too long");
// Initialize validators
for (uint256 i = 0; i < validators.length; i++) {
_installValidator(validators[i].module, validators[i].data);
}
// Initialize executors
for (uint256 i = 0; i < executors.length; i++) {
if (executors[i].module == address(0)) continue;
_installExecutor(executors[i].module, executors[i].data);
}
// Initialize hook
if (hook.module != address(0)) {
_installHook(hook.module, hook.data);
}
// Initialize fallback handlers
for (uint256 i = 0; i < fallbacks.length; i++) {
if (fallbacks[i].module == address(0)) continue;
_installFallbackHandler(fallbacks[i].module, fallbacks[i].data);
}
_configureRegistry(registry, attesters, threshold);
}

Code when testing using Foundry:

interface IERC7484 {
// Define any necessary functions or events here
}
struct BootstrapConfig {
address module;
bytes data;
}
contract RegistryBootstrap {
uint256 constant MAX_ARRAY_LENGTH = 50;
function initNexus(
BootstrapConfig[] calldata validators,
BootstrapConfig[] calldata executors,
BootstrapConfig calldata hook,
BootstrapConfig[] calldata fallbacks,
IERC7484 registry,
address[] calldata attesters,
uint8 threshold
) external {
require(validators.length <= MAX_ARRAY_LENGTH, "Validators array too long");
require(executors.length <= MAX_ARRAY_LENGTH, "Executors array too long");
require(fallbacks.length <= MAX_ARRAY_LENGTH, "Fallbacks array too long");
// Initialize validators
for (uint256 i = 0; i < validators.length; i++) {
_installValidator(validators[i].module, validators[i].data);
}
// Initialize executors
for (uint256 i = 0; i < executors.length; i++) {
if (executors[i].module == address(0)) continue;
_installExecutor(executors[i].module, executors[i].data);
}
// Initialize hook
if (hook.module != address(0)) {
_installHook(hook.module, hook.data);
}
// Initialize fallback handlers
for (uint256 i = 0; i < fallbacks.length; i++) {
if (fallbacks[i].module == address(0)) continue;
_installFallbackHandler(fallbacks[i].module, fallbacks[i].data);
}
_configureRegistry(registry, attesters, threshold);
}
function _installValidator(address module, bytes calldata data) internal {
// Logic to install validator
}
function _installExecutor(address module, bytes calldata data) internal {
// Logic to install executor
}
function _installHook(address module, bytes calldata data) internal {
// Logic to install hook
}
function _installFallbackHandler(address module, bytes calldata data) internal {
// Logic to install fallback handler
}
function _configureRegistry(IERC7484 registry, address[] calldata attesters, uint8 threshold) internal {
// Logic to configure registry
}
}

Foundry output:

Ran 4 tests for test/RegistryBootstrap.t.sol:RegistryBootstrapTest
[PASS] testExecutorsArrayTooLong() (gas: 38203)
[PASS] testFallbacksArrayTooLong() (gas: 38164)
[PASS] testInitNexus() (gas: 21143)
[PASS] testValidatorsArrayTooLong() (gas: 38132)
Suite result: ok. 4 passed; 0 failed; 0 skipped; finished in 51.48ms (35.66ms CPU time)

Ran 1 test suite in 107.19ms (51.48ms CPU time): 4 tests passed, 0 failed, 0 skipped (4 total tests)

Updates

Lead Judging Commences

0xnevi Lead Judge 11 months ago
Submission Judgement Published
Invalidated
Reason: Known issue
Assigned finding tags:

finding-loop-array-length-not-checked

Invalid [known issue [NonCritical-16]](https://github.com/Cyfrin/2024-07-biconomy/issues/1)

Support

FAQs

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