Gas griefing is a denial-of-service vulnerability where malicious users force transactions to consume excessive gas, either by failing late in execution or by triggering computationally expensive operations. While not directly stealing funds, gas griefing degrades protocol usability and can lock up user funds temporarily. Firepan's HOUND AI detects gas griefing vulnerabilities automatically during development and post-deployment monitoring, covering continuous analysis across the full contract lifecycle.
Gas griefing exploits the EVM's gas model to force transactions to waste resources. Attacker can:
Gas griefing differs from DoS in that the transaction must execute and eventually succeed—the griefing is in the resource consumption, not transaction failure.
Gas griefing typically involves:
// VULNERABLE — example only
// Demonstrates: Gas Griefing
// Do NOT use in production
pragma solidity ^0.8.0;
contract VulnerableGasGriefing {
mapping(address => uint256[]) public userTokens;
address[] public allUsers;
// VULNERABLE: Unbounded loop over user-controlled array
function transferTokens(address[] memory recipients, uint256[] memory amounts) public {
require(recipients.length == amounts.length);
// VULNERABLE: Loop size controlled by user
// Could iterate 1000+ times, each with SSTORE (20K gas)
for (uint i = 0; i < recipients.length; i++) {
balances[recipients[i]] += amounts[i]; // SSTORE: 20K gas each
}
}
// VULNERABLE: Unbounded loop over all users
function distributeRewards(uint256 reward) public onlyOwner {
// VULNERABLE: Gas griefing if attacker registers many users
for (uint i = 0; i < allUsers.length; i++) {
_transfer(allUsers[i], reward);
}
}
// VULNERABLE: External call loop
function callExternal(address[] memory targets) public {
for (uint i = 0; i < targets.length; i++) {
// VULNERABLE: External call might be expensive
(bool success, ) = targets[i].call("");
require(success);
}
}
// VULNERABLE: Storage loop
function processLargeArray(uint256[] calldata data) public {
for (uint i = 0; i < data.length; i++) {
storageArray[i] = data[i]; // SSTORE: 20K gas each
}
}
// VULNERABLE: Memory allocation
function allocateLargeArray(uint256 size) public {
uint256[] memory largeArray = new uint256[](size); // 32 gas per word
for (uint i = 0; i < size; i++) {
largeArray[i] = i;
}
}
}
contract GasGriefAttacker {
VulnerableGasGriefing public target;
function griefWithLoop() public {
// Create huge array to force expensive loop
address[] memory recipients = new address[](10000);
uint256[] memory amounts = new uint256[](10000);
for (uint i = 0; i < 10000; i++) {
recipients[i] = address(uint160(i));
amounts[i] = 1 wei;
}
// Call transferTokens with 10000 iterations
// Each iteration: SSTORE = 20K gas
// Total: 200M+ gas! (block gas limit is 30M)
target.transferTokens(recipients, amounts);
}
function griefWithStorage() public {
// Create array of size 1000
uint256[] memory data = new uint256[](1000);
for (uint i = 0; i < 1000; i++) {
data[i] = i;
}
// Call processLargeArray
// 1000 SSTORE operations = 20M+ gas
target.processLargeArray(data);
}
function registerManyUsers(address target_) public {
// Register 10000 dummy users in target contract
// Now distributeRewards() iterates 10000 times
// Forces 10000 expensive operations per distribution
}
}
| Protocol | Date | Loss | Root Cause | |----------|------|------|-----------| | SushiSwap | 2021 | User funds locked | Gas griefing on rebalancing function | | Uniswap V2 | 2020 | $100K+ in gas waste | Unbounded loop in swap routing | | Curve Finance | 2021 | Minor | Large deposit array causing high gas |
Manual detection requires gas consumption analysis:
Red flags:
Firepan's HOUND AI performs gas consumption analysis:
Firepan's HOUND AI engine identifies gas griefing vulnerabilities across all monitored contracts.
1. Bound Loop Iteration Count
Always limit loop iterations:
// VULNERABLE
function transfer(address[] memory recipients, uint256[] memory amounts) public {
for (uint i = 0; i < recipients.length; i++) {
balances[recipients[i]] += amounts[i];
}
}
// SECURE: Limit array length
function transfer(address[] memory recipients, uint256[] memory amounts) public {
require(recipients.length <= 100, "Array too large");
for (uint i = 0; i < recipients.length; i++) {
balances[recipients[i]] += amounts[i];
}
}
2. Use Pagination for Large Datasets
Process data in chunks instead of single transaction:
// SECURE: Paginated distribution
function distributeRewards(uint256 startIndex, uint256 endIndex) public onlyOwner {
require(endIndex - startIndex <= 100, "Batch too large");
for (uint i = startIndex; i < endIndex; i++) {
_transfer(allUsers[i], reward);
}
}
3. Avoid External Calls in Loops
Move external calls outside loops:
// VULNERABLE
function callMultiple(address[] memory targets) public {
for (uint i = 0; i < targets.length; i++) {
(bool success, ) = targets[i].call("");
require(success);
}
}
// SECURE: Make calls separately
function callOne(address target) public {
(bool success, ) = target.call("");
require(success);
}
4. Use Efficient Data Structures
Prefer efficient storage patterns:
// Inefficient: Loop over all addresses
address[] public users;
for (uint i = 0; i < users.length; i++) {
distribute(users[i]);
}
// Efficient: Store only active users
mapping(address => bool) public isActive;
address[] public activeUsers;
5. Implement Off-Chain Aggregation
Use off-chain computation for heavy lifting:
// Off-chain: Compute merkle root of all distributions
// On-chain: Verify merkle proofs and distribute
function claimReward(uint256 amount, bytes32[] calldata proof) public {
require(verify(msg.sender, amount, proof), "Invalid proof");
_transfer(msg.sender, amount);
}
Q: What is gas griefing in smart contracts?
A: Gas griefing exploits unbounded loops or expensive operations to force transactions to consume excessive gas, causing them to fail or be prohibitively expensive. Attacker doesn't steal funds but degrades protocol usability.
Q: Which protocols have been exploited via gas griefing?
A: SushiSwap (2021) suffered gas griefing on rebalancing. Uniswap V2 (2020) had high gas consumption in swap routing. Curve Finance (2021) experienced gas issues with large deposits. Aggregate impact on usability is significant.
Q: How does Firepan detect gas griefing?
A: Firepan detects loops, analyzes iteration bounds, estimates gas per iteration, models total gas consumption, checks against block limits, and constructs griefing scenarios.
Q: Can gas griefing be exploited after deployment?
A: Yes, gas griefing is immediately exploitable post-deployment. Any unbounded loop can be targeted with large inputs to consume excessive gas.
Q: How do I prevent gas griefing?
A: Bound all loop iterations (max 100 iterations per transaction). Use pagination for large datasets. Avoid external calls in loops. Use efficient data structures. Implement off-chain aggregation for heavy computation.
Gas griefing degrades protocol usability and can temporarily lock user funds. While less severe than direct theft, it affects user experience and protocol reliability. Bounding loop iterations and using pagination prevents the vast majority of gas griefing risks. Firepan's HOUND AI detects unbounded loops and expensive operations 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 →