Snowman Merkle Airdrop

AI First Flight #10
Beginner FriendlyFoundrySolidityNFT
EXP
View results
Submission Details
Impact: high
Likelihood: high
Invalid

Snow::burn allows burning any user's Snow without allowance - attacker can grief all claims

Root + Impact: // src/Snow.sol
contract Snow is ERC20 {
// @> BUG: burn() / burnFrom() me allowance check nahi hai
// @> BUG: Koi bhi kisi ke bhi Snow burn kar sakta hai
function burn(address from, uint256 amount) external {
_burn(from, amount); // no allowance, no msg.sender == from check
}
// Normal ERC20Burnable me burnFrom() allowance check karta hai,
// yahan wo check missing hai
}

Description: Description: Missing allowance check in Snow burn allows attacker to burn victim's Snow and block claims

Snow token ko claim karne ke liye chahiye. User ko Snow hold karke SnowmanAirdrop.claimSnowman() call karna hota hai.
​
Par Snow.sol me burn() function me ye check hi nahi hai ki burn karne wala wahi hai jiska Snow hai, ya uske paas allowance hai ya nahi.
​
Attacker kisi bhi victim ka address daal ke uska Snow burn kar sakta hai. Victim ka Snow 0 ho jayega, to wo claim nahi kar payega. Attacker pure airdrop ke saare users ka Snow jala ke sabka claim rok sakta hai.
​
Result: Ek transaction se kisi ka bhi Snow khatam, sabka claim DoS.

Risk

Likelihood:High - Attacker ko victim ki private key nahi chahiye. Bas victim ka address public hai, aur burn() public hai. Ek loop me 100 users ka Snow jala sakta hai.

Impact:High - Victims ka Snow gayab, wo NFT claim nahi kar payenge. Snow ki value aur trust dono khatam. Attacker bina paisa kharch kiye poora airdrop rok sakta hai.

Proof of Concept: High - Victims ka Snow gayab, wo NFT claim nahi kar payenge. Snow ki value aur trust dono khatam. Attacker bina paisa kharch kiye poora airdrop rok sakta hai.

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.24;
import {Test} from "forge-std/Test.sol";
import {Snow} from "../src/Snow.sol";
​
contract BurnGriefTest is Test {
Snow snow;
address victim = makeAddr("victim");
address attacker = makeAddr("attacker");
function setUp() public {
snow = new Snow();
// Victim ko 100 Snow mint karke do
snow.mint(victim, 100 ether);
}
function test_AttackerBurnsVictimSnow() public {
assertEq(snow.balanceOf(victim), 100 ether);
// Attacker ke paas koi allowance nahi, phir bhi burn kar deta hai
vm.prank(attacker);
snow.burn(victim, 100 ether);
// Victim ka Snow 0 ho gaya - BUG, hona nahi chahiye tha
assertEq(snow.balanceOf(victim), 0);
// Ab victim claimSnowman() nahi kar payega, Snow hi nahi hai
}
}

Recommended Mitigation: Mitigation: Add allowance check + only msg.sender can burn own Snow

- remove this code
+ add this code
Root Cause:
burn() me msg.sender == from ya allowance ka check missing hai.
​
Why this fix works:
Agar sirf owner hi apna Snow burn kar sake, ya jiske paas allowance hai wahi burn kar sake, to attacker victim ka Snow nahi jala payega. OpenZeppelin ka ERC20Burnable yahi karta hai.
​
Recommended Fix - Step by Step:
​
Step 1 - Use OpenZeppelin ERC20Burnable:
burn() sirf msg.sender ka Snow burn kare, burnFrom() allowance check kare.
​
Step 2 - Add allowance check in burnFrom():
Require allowance[from][msg.sender] >= amount, phir allowance kam karo, phir burn karo.
​
Step 3 - Remove custom burn(address, amount):
Custom burn(address) function ko hata do, sirf standard burn() aur burnFrom() rakho.
​
After Fix Verification:
- Victim apna Snow burn kare -> should SUCCEED
- Attacker bina allowance ke victim ka Snow burn kare -> should REVERT
- Airdrop contract allowance ke saath burn kare -> should SUCCEED
​
Fix Code:
​
// In Snow.sol - use standard OpenZeppelin
import {ERC20Burnable} from "@openzeppelin/contracts/token/ERC20/extensions/ERC20Burnable.sol";
contract Snow is ERC20, ERC20Burnable {
// Remove custom burn(address, amount)
// burn() -> only burns msg.sender's tokens
// burnFrom(from, amount) -> checks allowance first
}
Updates

Lead Judging Commences

ai-first-flight-judge Lead Judge 24 minutes ago
Submission Judgement Published
Invalidated
Reason: Incorrect statement

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.

Give us feedback!