high

Denial of Service (DoS): How It Works, Real Exploits & Automated Detection

April 1, 2026
Chainsethereumarbitrumbaseoptimismpolygonbnb-chain
Detected byslithermythrilechidnahound-ai

Denial of Service (DoS) vulnerabilities allow attackers to block legitimate users from accessing contract functionality. Unlike financial exploits, DoS attacks disable operations: preventing withdrawals, freezing governance, or bricking key functions. Protocols have lost operational availability for weeks due to DoS vulnerabilities. Firepan's HOUND AI detects DoS vulnerabilities automatically during development and post-deployment monitoring, covering continuous analysis across the full contract lifecycle.

What Is Denial of Service?

Denial of Service in smart contracts prevents legitimate users from executing intended actions. Common DoS vectors:

  1. Revert patterns: Attacker calls functions that force revert, blocking contract execution
  2. Unbounded loops: Attacker supplies large arrays causing out-of-gas
  3. External call failures: Contract relies on external call success; attacker's contract reverts
  4. Access control lockout: Owner/admin functions locked due to authorization bypass
  5. State lock: Contract enters unrecoverable state, blocking all operations
  6. Event log overflow: Emit unbounded events until contract is unqueryable
  7. Withdrawal loops: Attacker's contract's receive() reverts, blocking others' withdrawals

The vulnerability is critical because:

  • Breaks functionality: Users can't withdraw funds or participate
  • Irreversibility: Sometimes unfixable without upgrade
  • Cascading failures: One DoS can trigger cascading failures across dependent protocols

How Denial of Service Works

DoS exploitation involves:

  1. Identify vulnerable pattern: Find withdrawal loop, governance, or state-dependent logic
  2. Force failure: Craft input that causes transaction to revert
  3. Block others: Once attacker's transaction fails, others' transactions also fail
  4. Denial continues: Attacker repeats attack, maintaining DoS state
// VULNERABLE — example only
// Demonstrates: Denial of Service
// Do NOT use in production

pragma solidity ^0.8.0;

contract VulnerablePaymentSplitter {
    address[] public recipients;
    mapping(address => uint256) public shares;

    // VULNERABLE: Unbounded loop in distribution
    function distributeRewards(uint256 reward) public {
        // Loop over all recipients
        for (uint i = 0; i < recipients.length; i++) {
            uint256 share = (reward * shares[recipients[i]]) / 100;

            // VULNERABLE: If any recipient's receive() reverts, entire transaction reverts
            (bool success, ) = recipients[i].call{value: share}("");
            require(success);  // Reverts if ANY recipient reverts
        }
    }
}

contract VulnerableWithdrawal {
    mapping(address => uint256) public balances;

    // VULNERABLE: Withdrawal loop can be blocked
    function withdrawAll(address[] memory users) public onlyOwner {
        for (uint i = 0; i < users.length; i++) {
            uint256 amount = balances[users[i]];
            (bool success, ) = users[i].call{value: amount}("");
            require(success);  // Reverts if any user reverts

            balances[users[i]] = 0;
        }
    }
}

contract VulnerableGovernance {
    address[] public voters;

    // VULNERABLE: Unbounded loop can be exploited for DoS
    function executeVote(bytes memory proposal) public {
        // Loop over all voters to check votes
        for (uint i = 0; i < voters.length; i++) {
            _checkVote(voters[i]);
        }

        // If attacker registers 10000+ voters, loop becomes expensive
        // Subsequent votes become impossible (out of gas)
    }
}

contract DoSAttacker {
    VulnerablePaymentSplitter public target;

    constructor(address _target) {
        target = VulnerablePaymentSplitter(_target);
    }

    // STEP 1: Register as recipient
    function registerAsRecipient() public {
        target.registerRecipient(address(this));
    }

    // STEP 2: Revert on receive, blocking distribution
    receive() external payable {
        revert("Blocking distribution!");  // This blocks entire transaction!
    }

    function triggerDoS() public {
        // Calling distributeRewards() now reverts because our receive() reverts
        // Other recipients can't get paid
        target.distributeRewards(100 ether);
    }
}

contract UnboundedLoopDoS {
    // Register 10000 voters
    function registerManyVoters(address governance) public {
        for (uint i = 0; i < 10000; i++) {
            // Register dummy voter
            // executeVote() now loops 10000 times, burning gas
            // DoS subsequent votes
        }
    }
}

Real-World Denial of Service Exploits

| Protocol | Date | Impact | Root Cause | |----------|------|--------|-----------| | SynapseBridge | 2021 | Week outage | Unbounded loop in distribution | | PolyNetwork | 2021 | Partial freeze | External call failures blocking withdrawals | | Generic Governance | 2020-2023 | Multiple incidents | Unbounded voter loops |

How to Detect Denial of Service

Manual detection requires flow analysis:

  • External calls in loops: Identify external calls within loops
  • Require on external success: Flag require(success) on external calls
  • Unbounded loops: Find loops with user-controlled iteration count
  • State-dependent execution: Identify functions that block based on state
  • Single point of failure: Find if one actor can block others' operations
  • Authorization dependencies: Check if owner DoS impacts all users

Red flags:

  • External call within loop, require() on success
  • Unbounded loop over user-controlled array
  • require() blocking entire transaction on any failure
  • Single address in critical path
  • No pagination for large datasets
  • Loop over all users/recipients

How Firepan Detects Denial of Service Automatically

Firepan's HOUND AI performs DoS vulnerability analysis:

  1. External call enumeration: Identifies calls outside loops and within
  2. Loop bound analysis: Verifies iteration counts are bounded
  3. Require statement analysis: Flags require() statements in loops that can block execution
  4. Revert path finding: Constructs scenarios where attacker's contract reverts
  5. State lock detection: Identifies unrecoverable contract states
  6. Single point of failure: Flags critical functions with one-address dependency

Firepan's HOUND AI engine identifies DoS vulnerabilities across all monitored contracts.

Prevention Best Practices

1. Pull Over Push Pattern

Let users withdraw instead of pushing to them:

// VULNERABLE: Push pattern can be blocked
function distributeRewards() public {
    for (uint i = 0; i < recipients.length; i++) {
        (bool success, ) = recipients[i].call{value: reward}("");
        require(success);  // Blocks entire distribution!
    }
}

// SECURE: Pull pattern
mapping(address => uint256) public claimable;

function depositRewards(uint256 reward) public {
    for (uint i = 0; i < recipients.length; i++) {
        claimable[recipients[i]] += reward;
    }
}

function claim() public {
    uint256 amount = claimable[msg.sender];
    claimable[msg.sender] = 0;

    (bool success, ) = msg.sender.call{value: amount}("");
    require(success);
}

2. Don't Require External Call Success in Loops

Allow individual failures without blocking others:

// VULNERABLE
for (uint i = 0; i < recipients.length; i++) {
    (bool success, ) = recipients[i].call{value: share}("");
    require(success);  // Blocks entire loop!
}

// SECURE: Continue on failure
for (uint i = 0; i < recipients.length; i++) {
    (bool success, ) = recipients[i].call{value: share}("");
    // Don't require success; continue regardless
}

3. Use Pagination

Process data in chunks:

// SECURE: Paginated distribution
function distributeBatch(uint256 startIdx, uint256 endIdx) public onlyOwner {
    require(endIdx - startIdx <= 100, "Batch too large");

    for (uint i = startIdx; i < endIdx; i++) {
        _distribute(recipients[i]);
    }
}

4. Implement Emergency Pause

Allow circuit breaker for stuck operations:

bool public paused;

function pause() public onlyOwner {
    paused = true;
}

function unpause() public onlyOwner {
    paused = false;
}

function distribution() public {
    require(!paused, "Paused");
    // ...
}

5. Use Try-Catch for External Calls

Gracefully handle failures:

// SECURE: Try-catch
try target.call{value: amount}("") {} catch {
    // Silently fail; continue
}

Frequently Asked Questions

Q: What is denial of service in smart contracts?

A: Denial of Service exploits prevent legitimate users from accessing contract functionality. Attackers might cause loops to revert, block withdrawals, or freeze governance, making the contract unusable.


Q: Which protocols have been exploited via DoS?

A: SynapseBridge (2021) suffered week-long outage from unbounded loop. PolyNetwork (2021) had partial freeze from external call failures. Generic governance protocols regularly face DoS from unbounded voter loops.


Q: How does Firepan detect DoS?

A: Firepan identifies external calls in loops, verifies loop bounds, flags require() statements that block execution, constructs revert scenarios, detects state locks, and identifies single points of failure.


Q: Can DoS be exploited after deployment?

A: Yes, DoS is immediately exploitable post-deployment. Attackers can block withdrawals, freeze governance, or brick operations within hours of deployment.


Q: How do I prevent DoS?

A: Use pull pattern instead of push. Don't require external call success in loops. Use pagination for large datasets. Implement emergency pause. Use try-catch for external calls. Avoid single points of failure.

Conclusion

Denial of Service has impacted protocol availability for weeks, making it a critical vulnerability class. SynapseBridge's week-long outage demonstrated the impact. Using pull patterns, pagination, and try-catch for external calls prevents the vast majority of DoS vulnerabilities. Firepan's HOUND AI detects DoS-vulnerable patterns across all monitored contracts.

Start securing your smart contracts at https://app.firepan.com/

Firepan

Scan Your Contracts Now

12,453 contracts secured. 2,851 vulnerabilities blocked. 236 exploits prevented. Run a free surface scan — results in minutes, no credit card required.

Run Free Scan →