dos-griefing-analysis
Detects Denial of Service and griefing vulnerabilities in smart contracts. Covers unbounded loop DoS, block gas limit exhaustion, external call failure DoS, insufficient gas griefing (63/64 rule), storage bloat attacks, timestamp griefing, self-destruct force-feeding, and push vs pull payment pattern analysis. Use when auditing contracts with batch operations, loops over user data, reward distribution, dividend systems, or any logic that depends on address(this).balance or iterates over growing collections.
git clone --depth 1 https://github.com/quillai-network/quillshield_skills /tmp/dos-griefing-analysis && cp -r /tmp/dos-griefing-analysis/plugins/dos-griefing-analysis/skills/dos-griefing-analysis ~/.claude/skills/dos-griefing-analysisSKILL.md
# DoS & Griefing Analysis
Detect vulnerabilities that allow attackers to **make contracts unusable** (Denial of Service) or **harm other users at low cost** (griefing). These attacks don't steal funds directly but can permanently brick contracts or block critical operations.
## When to Use
- Auditing contracts with loops over dynamic arrays or mappings
- Reviewing batch operations (airdrops, reward distribution, liquidation)
- Analyzing contracts that rely on `address(this).balance` for logic
- Verifying that individual user failures don't block system-wide operations
- Checking for gas-based attack vectors (insufficient gas, storage bloat)
## When NOT to Use
- Direct fund theft analysis (use behavioral-state-analysis)
- Access control consistency (use semantic-guard-analysis)
- Reentrancy detection (use reentrancy-pattern-analysis)
## Seven DoS & Griefing Vulnerability Classes
### Class 1: Unbounded Loop DoS
Loops that iterate over collections that grow with contract usage. As the collection grows, gas cost increases until the function exceeds the block gas limit and becomes permanently uncallable.
```solidity
// VULNERABLE: Loop over all users — grows forever
address[] public allUsers;
function distributeRewards() external {
for (uint i = 0; i < allUsers.length; i++) {
// If allUsers has 10,000+ entries, this exceeds block gas limit
token.transfer(allUsers[i], calculateReward(allUsers[i]));
}
}
// SAFE: Paginated processing
function distributeRewards(uint256 startIndex, uint256 batchSize) external {
uint256 end = min(startIndex + batchSize, allUsers.length);
for (uint i = startIndex; i < end; i++) {
token.transfer(allUsers[i], calculateReward(allUsers[i]));
}
}
// SAFER: Pull pattern
mapping(address => uint256) public pendingRewards;
function claimReward() external {
uint256 reward = pendingRewards[msg.sender];
pendingRewards[msg.sender] = 0;
token.transfer(msg.sender, reward);
}
```
**Detection:**
```
For each loop in the contract:
1. What determines the loop bound?
- Fixed constant → SAFE
- Constructor parameter → SAFE (if reasonable)
- Dynamic array length → POTENTIALLY VULNERABLE
- Mapping iteration → VULNERABLE (can't iterate mappings, but workaround arrays are vulnerable)
2. Can the loop bound grow with contract usage?
3. What is the gas cost per iteration?
4. At what size does total gas exceed 30M? (block gas limit)
If loop_bound is unbounded AND gas_per_iteration > 30M / estimated_max_users:
→ UNBOUNDED LOOP DOS
```
### Class 2: External Call Failure DoS
A single failed external call in a batch operation blocks all other operations.
```solidity
// VULNERABLE: One blacklisted user blocks ALL distributions
function distributeToAll(address[] calldata users, uint256[] calldata amounts) external {
for (uint i = 0; i < users.length; i++) {
// If users[5] is USDC-blacklisted, this reverts for ALL users
require(token.transfer(users[i], amounts[i]), "Transfer failed");
}
}
// SAFE: Handle failures individually
function distributeToAll(address[] calldata users, uint256[] calldata amounts) external {
for (uint i = 0; i < users.length; i++) {
try IERC20(token).transfer(users[i], amounts[i]) returns (bool success) {
if (!success) emit TransferFailed(users[i], amounts[i]);
} catch {
emit TransferFailed(users[i], amounts[i]);
}
}
}
```
**Detection:**
```
For each loop containing external calls:
1. Does a failed call revert the entire transaction? (require/revert)
2. Is there try/catch or success-check-and-skip?
3. Can any single address/user cause the call to fail?
- Blacklisted address
- Contract that reverts in receive()
- Address that runs out of gas
If yes → EXTERNAL CALL FAILURE DOS
```
### Class 3: Insufficient Gas Griefing (63/64 Rule)
EIP-150's 63/64 rule: when making an external call, only 63/64 of remaining gas is forwarded. An attacker can supply just enough gas for the outer function to succeed while the inner call fails.
```solidity
// VULNERABLE: Relayer pattern without gas check
function executeMetaTx(address target, bytes calldata data) external {
// Attacker (relayer) provides just enough gas for this function
// but NOT enough for target.call(data) to succeed
(bool success, ) = target.call(data);
// success = false (ran out of gas), but function doesn't revert!
// Mark meta-tx as executed even though it failed
executedTxs[txHash] = true; // Meta-tx permanently "used" but never executed
}
// SAFE: Verify sufficient gas and check success
function executeMetaTx(address target, bytes calldata data, uint256 gasLimit) external {
require(gasleft() >= gasLimit * 64 / 63 + 5000, "Insufficient gas");
(bool success, ) = target.call{gas: gasLimit}(data);
require(success, "Execution failed");
}
```
**Detection:**
```
For each function that makes external calls:
1. Does the function check the success of the call?
2. If success is not required, does failure cause permanent state changes?
3. Is the function called by untrusted relayers?
4. Is there a minimum gas check before the external call?
If no success check AND permanent state change on failure:
→ INSUFFICIENT GAS GRIEFING
```
### Class 4: Storage Bloat Attack
An attacker fills storage arrays/mappings to increase gas costs for other users.
```solidity
// VULNERABLE: Anyone can add entries, increasing gas for iteration
mapping(address => address[]) public userTokens;
function addToken(address token) external {
userTokens[msg.sender].push(token);
// No limit on how many tokens a user can add
// Functions that iterate userTokens[user] become expensive
}
function getUserValue(address user) external view returns (uint256) {
uint256 total = 0;
for (uint i = 0; i < userTokens[user].length; i++) {
// Gas cost grows linearly with array sizeToken-efficient smart contract security auditing via Behavioral State Analysis (BSA). Scopes analysis to contract type, runs only relevant threat engines, and uses tiered output depth. Use for auditing smart contracts, security reviews, or DeFi threat modeling.
Blue-team release-gate analysis for smart contract deployment and upgrade readiness. Classifies repositories, checks deploy/upgrade execution paths, CI/CD trust boundaries, config drift, secrets/signer operational security, and outputs evidence-backed release verdicts.
Detects unsafe external call patterns and token integration vulnerabilities in smart contracts. Covers unchecked call/delegatecall/staticcall return values, fee-on-transfer tokens, rebasing tokens, tokens with missing return values (USDT), ERC-777 callback risks, unsafe approve race conditions, return data bombs, gas stipend limitations, and push vs pull payment patterns. Use when auditing contracts that interact with external contracts, integrate arbitrary ERC20 tokens, distribute payments, or make low-level calls.
Detects input validation failures and arithmetic vulnerabilities in smart contracts. Covers missing zero-address and zero-amount checks, division-before-multiplication precision loss, rounding direction exploitation, ERC4626 vault share inflation attacks, unsafe integer casting, dust amount exploitation, and Solidity 0.8+ unchecked block edge cases. Use when auditing contracts with fee calculations, share pricing, exchange rates, unchecked blocks, or any public-facing functions that accept user input.
Detects price oracle manipulation and flash loan attack vectors in DeFi smart contracts. Classifies oracle trust models (Chainlink, TWAP, spot price, custom), identifies stale price risks, circular price dependencies, and flash loan atomicity exploitation patterns. Use when auditing DeFi protocols that depend on price data, oracle integrations, lending protocols, DEXs, derivatives, or any contract where flash loans could manipulate state within a single transaction.
Detects vulnerabilities in upgradeable proxy smart contracts including storage layout collisions, uninitialized implementations, function selector clashing, delegatecall context issues, and upgrade path safety. Covers Transparent Proxy, UUPS (EIP-1822), Beacon, Diamond (EIP-2535), and Minimal Proxy (EIP-1167) patterns. Use when auditing upgradeable contracts, reviewing implementation upgrades, analyzing delegatecall architectures, or verifying proxy pattern compliance.
Systematically detects all reentrancy vulnerability variants in smart contracts — classic, cross-function, cross-contract, and read-only reentrancy. Builds call graphs, verifies CEI (Checks-Effects-Interactions) pattern compliance, traces state changes relative to external calls, and identifies callback vectors through ERC-777/ERC-1155 hooks. Use when auditing contracts that make external calls, transfer ETH or tokens, interact with callback-enabled standards, or have complex multi-contract architectures.
Detects logic vulnerabilities in smart contracts by analyzing guard-state consistency patterns. Identifies functions that bypass security checks (require, modifiers) that other functions consistently apply. Uses the Consistency Principle — a contract is its own specification. Use when auditing smart contracts for missing access controls, inconsistent pause checks, logic bugs, forgotten modifiers, or when traditional tools report no issues but logic errors may exist.