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.
Denial of Service in smart contracts prevents legitimate users from executing intended actions. Common DoS vectors:
The vulnerability is critical because:
DoS exploitation involves:
// 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
}
}
}
| 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 |
Manual detection requires flow analysis:
Red flags:
Firepan's HOUND AI performs DoS vulnerability analysis:
Firepan's HOUND AI engine identifies DoS vulnerabilities across all monitored contracts.
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
}
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.
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
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 →