Gas Griefing
id: LS02M
title: Gas Griefing
baseSeverity: M
category: gas-griefing
language: solidity
blockchain: [ethereum]
impact: Denial of service, refund blockage, or UX degradation
status: draft
complexity: medium
attack_vector: external
mitigation_difficulty: medium
versions: [">=0.6.0", "<0.8.21"]
cwe: CWE-400
swc: SWC-136
📝 Description
- Gas Griefing occurs when an attacker exploits gas limitations or fallback behavior to make a function unusable or undesirably expensive.
- This can happen when:
- A contract calls untrusted external addresses that revert or consume all gas.
- Gas stipends (e.g.,
2300gas intransfer) are insufficient for smart contract recipients. - Refunds, loops, or bulk processing are blocked due to one recipient failing or consuming all gas.
- This leads to denial of service (DoS) or degraded user experience, especially in payout or voting systems.
🚨 Vulnerable Code
contract Airdrop {
mapping(address => bool) public claimed;
function claim(address[] calldata recipients) external {
for (uint i = 0; i < recipients.length; i++) {
if (!claimed[recipients[i]]) {
payable(recipients[i]).transfer(1 ether); // ❌ fails if any recipient reverts
claimed[recipients[i]] = true;
}
}
}
receive() external payable {}
}
🧪 Exploit Scenario
Step-by-step exploit process:
- Attacker deploys a contract with a fallback function that always reverts or consumes all gas.
- Attacker gets included in the recipients list for a bulk payout.
- When claim() is called, the call to the attacker's address fails or runs out of gas.
- The entire loop or transaction fails, preventing anyone from receiving their payout.
Assumptions:
- The loop or execution does not handle failed calls gracefully.
- No gas-limiting mechanism (try/catch, call.value().gas()) is used.
✅ Fixed Code
function claim(address[] calldata recipients) external {
for (uint i = 0; i < recipients.length; i++) {
if (!claimed[recipients[i]]) {
claimed[recipients[i]] = true;
(bool sent, ) = payable(recipients[i]).call{value: 1 ether, gas: 5000}(""); // ✅ safe call
if (!sent) {
// optionally log failure
}
}
}
}
🧭 Contextual Severity
- context: "Default"
severity: M
reasoning: "Can block execution, but not a direct exploit unless critical paths are affected."
- context: "Reward distribution in yield protocols"
severity: H
reasoning: "Stuck funds and failed distributions lead to major user impact and protocol failure."
- context: "Non-critical analytics or reporting loop"
severity: L
reasoning: "Only informational breakdown without asset or control consequences."
🛡️ Prevention
Primary Defenses
- Use low-level call with gas limits instead of transfer or send.
- Handle failed transfers gracefully using pull payment patterns.
- Do not allow untrusted external logic (e.g., looping over arbitrary addresses).
Additional Safeguards
- Log failed calls and allow users to retry (pull-based withdrawals).
- Use batching to avoid single-point failure in loops.
- Avoid using recipient contracts for sensitive logic unless whitelisted.
Detection Methods
- Slither: unchecked-low-level-calls, dos-loop, and transfer-usage detectors.
- Manual audit of loop + external call patterns.
- Gas profiling tools (Tenderly, Remix) to simulate edge cases.
🕰️ Historical Exploits
- Name: Relayer Contract Gas Griefing
- Date: Unspecified
- Loss: Potential denial-of-service (DoS) impact
- Post-mortem: Link to post-mortem
📚 Further Reading
- Insufficient Gas Griefing walkthrough – Bailsec.io
- Understanding Smart Contract Gas Griefing Attacks – Orochi Network
- Secure Gas Forwarding in Smart Contracts: Preventing Insufficient Gas – Varkiwi
✅ Vulnerability Report
id: LS02M
title: Gas Griefing
severity: M
score:
impact: 3
exploitability: 3
reachability: 4
complexity: 2
detectability: 4
finalScore: 3.25
📄 Justifications & Analysis
- Impact: Affects availability—can lock out legitimate users from claiming funds.
- Exploitability: Attacker only needs a revert/fallback contract.
- Reachability: Frequently present in token airdrops, reward distributions.
- Complexity: Low to medium—attack requires deploying a smart contract with revert logic.
- Detectability: Easily caught by static tools and audit if patterns are known.