mcpField
W
web3-audit

web3-audit

github.com/uphiago安全1.3k39 次安装8 周前更新
代码仓库

关于 web3-audit

web3-audit 是面向安全研究人员的智能合约审计技能,提供目标筛选方法、漏洞模式、代码搜索建议和审计示例,用于检查 Web3 协议。

主要功能

  1. 01审计前目标筛选
  2. 02十类智能合约漏洞
  3. 03Solidity 搜索模式
  4. 04对照同组函数
  5. 05Foundry PoC 模板
  6. 06真实付费漏洞案例

适用场景

  1. 01审计前筛选赏金目标
  2. 02检查记账与访问控制逻辑
  3. 03比较相关合约代码路径
  4. 04编写概念验证测试

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/uphiago/recon-skills --skill web3-audit

安装后在 Claude Code 中输入/web3-audit确认已加载。

详细介绍

Web3 智能合约审计

10 类漏洞。审计前的止损信号。Foundry PoC 模板。真实付费案例。


审计前止损信号(代码审查前务必检查)

ZKsync 的教训:3.22 亿美元 TVL + OZ 审计 + 75 万行代码 + 5 次审计 = 0 个发现。大型且经过充分审计的跨链桥极难发现问题。

  1. TVL < $500K → 最高奖金太低,不值得投入精力
  2. 有 2 次或更多顶级审计(Halborn、ToB、Cyfrin、OpenZeppelin),且协议简单 → 漏洞已经被发现
  3. 协议代码 < 500 行,只有单一的 A→B→C 流程 → 攻击面极小
  4. 公式:max_realistic_payout = min(10% × TVL, program_cap) — 如果低于 $10K,就跳过

软性止损: 当前版本经过 OZ/ToB/Cyfrin 审计,且代码库 > 50 万行 → 预计要花 40 小时以上,可能只找到 1 个问题。只有在奖金下限 > $50K 且你具备该协议的专业知识时才继续。

目标评分(>= 6/10 才继续):

  • TVL > $10M:+2
  • Immunefi 计划的 Critical 奖金 >= $50K:+2
  • 当前版本未经顶级审计:+2
  • 距离部署时间 < 30 天:+1
  • 你以前审计过该协议:+1
  • 有源代码 + natspec 注释:+1
  • 可升级代理:+1

唯一规则

“阅读所有同类函数。如果 vote() 有修饰符,就检查 poke()、reset()、harvest()。同类函数缺少修饰符本身就是漏洞。”

这一条规则可以解释 Immunefi 上 19% 的 Critical 发现。


1. 记账状态不同步

排名第 1 的 Critical 漏洞类别——占 Immunefi 上所有 Critical 的 28%。

漏洞是什么

两个状态变量本应保持同步。某条代码路径更新了 A,却忘记更新 B。后续代码读取这两个变量,并依据过期的 B 作出判断。

Real Value = A - B
If A updated but B isn't → Real Value appears larger → phantom value
根因模式

变体 1:虚假收益(Yeet 协议——35 份重复报告)

function startUnstake(uint256 amount) external {
    totalSupply -= amount;  // decremented BEFORE transfer
    // aToken.balanceOf(this) still reflects old value
    // yieldAmount = aToken.balanceOf - totalSupply = phantom yield
}

变体 2:快速路径跳过状态更新(Alchemix V3)

function claimRedemption(uint256 tokenId) external {
    if (transmuter.balance >= amount) {
        transmuter.transfer(user, amount);
        _burn(tokenId);
        return;  // EARLY RETURN — cumulativeEarmarked, _redemptionWeight, totalDebt never updated
    }
    // Slow path: updates all state vars correctly
    alchemist.redeem(...);
}

变体 3:更新顺序错误(Alchemix)

function deposit(uint256 amount) external {
    _shares = (amount * totalShares) / totalAssets;  // calculated BEFORE deposit
    totalAssets += amount;   // assets added AFTER shares calculated → wrong rate
}
Grep 模式
# Find all accounting variables
grep -rn "totalSupply\|totalShares\|totalAssets\|totalDebt\|cumulativeReward\|rewardPerShare" contracts/

# Find all early returns in claim/redeem functions
grep -rn "\breturn\b" contracts/ -B3 | grep -B3 "if\b"

# For each early return: which state updates in normal path are skipped?

2. 访问控制

排名第 2 的 Critical——占 Critical 的 19%。仅 2024 年就损失了 9.53 亿美元。

变体 1:同类函数缺少修饰符
function vote(uint256 tokenId) external onlyNewEpoch(tokenId) {  // guarded
function reset(uint256 tokenId) external onlyNewEpoch(tokenId) { // guarded
function poke(uint256 tokenId) external {                         // NO GUARD → infinite FLUX inflation
}
变体 2:检查错误(是否存在,而非是否拥有)
function split(uint256 tokenId, uint256 amount) external {
    _requireOwned(tokenId);  // checks if token EXISTS, not if caller OWNS it
    _burn(tokenId);
    _mint(msg.sender, amount);  // attacker steals tokens they don't own
}
变体 3:无提示修饰符(if 而非 require)
// VULNERABLE — non-admin silently gets through:
modifier onlyAdmin() {
    if (msg.sender == admin) {
        _;  // body only executes for admin, but non-admin doesn't revert
    }
}
// CORRECT: require(msg.sender == admin, "Not admin"); _;
变体 4:代理未初始化
function initialize(address _owner) public {  // MISSING: initializer modifier
    owner = _owner;  // anyone can call → become owner
}
// Fix: constructor() { _disableInitializers(); }
Grep 模式
# Find sibling function families — do ALL have the same modifier set?
grep -rn "function vote\|function poke\|function reset\|function update\|function claim\|function harvest" contracts/ -A2

# Ownership check: existence vs ownership?
grep -rn "_requireOwned\|ownerOf\|_isApprovedOrOwner\|_checkAuthorized" contracts/ -B5

# Silent modifiers
grep -rn "modifier\b" contracts/ -A8 | grep -B3 "if (" | grep -v "require\|revert"

# Uninitialized initializer
grep -rn "function initialize\b" contracts/ -A3
grep -rn "_disableInitializers()" contracts/
真实付费案例
协议奖金漏洞
Wormhole$10MUUPS 代理未初始化 → 任何人都能调用 initialize()
ZeroLend不适用split() 检查是否存在,而非是否拥有
Alchemix不适用poke() 缺少 onlyNewEpoch → FLUX 无限增发
Parity冻结 $150M库中的 initWallet() 没有访问控制

3. 代码路径不完整

排名第 3 的 Critical——占 Critical 的 17%。

函数族对比测试
1. List all state changes in function A (deposit/place/create)
2. List all state changes in function B (withdraw/update/cancel)
3. For each state change in A: does B have the corresponding reverse?
4. For each token transfer in A: does B have the corresponding refund?
If A does X but B doesn't do the reverse of X → BUG.
变体 1:更新函数遗漏退款(ThunderNFT)
function place_order(OrderInput calldata order) external {
    token.safeTransferFrom(msg.sender, address(this), order.price);  // takes tokens
    orders[orderId] = order;
}
function update_order(OrderInput calldata updatedOrder) external {
    // BUG: NO REFUND for sell orders when price decreases → tokens permanently stuck
    orders[orderId] = updatedOrder;
}
变体 2:部分成交的代币被卡住(Plume)
function swapForETH(uint256 amountIn) external {
    token.safeTransferFrom(msg.sender, address(this), amountIn);
    uint256 filled = dex.swap(amountIn);  // partial fill possible
    _refundExcessEth(amountIn - filled);  // BUG: refunds ETH only, not ERC20
}
变体 3:mint() 绕过了 deposit() 中的检查(MetaPool)
function deposit(uint256 assets, address receiver) public override {
    shares = _deposit(assets, receiver);  // includes receipt validation
}
function mint(uint256 shares, address receiver) public override {
    assets = convertToAssets(shares);
    _mint(receiver, shares);  // MISSING: _deposit() validation → mints without receiving assets
}
Grep 模式
grep -rn "function place_\|function create_\|function add_\|function open_" contracts/ -A5
grep -rn "function update_\|function modify_\|function cancel_" contracts/ -A5
grep -rn "safeApprove\b" contracts/    # safeApprove without zero-reset before
grep -rn "delete\b" contracts/ -B5 -A5  # delete before operation completes
grep -rn "function deposit\|function mint\|function withdraw\|function redeem" contracts/ -A10

4. 差一错误与边界条件

排名第 4 的 High——占 High 的 22%。只改一个字符,影响巨大。

根因
// VeChain Stargate — post-exit reward drain:
function _claimableDelegationPeriods(address delegator) internal view returns (uint256) {
    if (endPeriod > nextClaimablePeriod) {  // BUG: should be >=
        return 0;  // exited users get nothing
    }
    return nextClaimablePeriod - lastClaimedPeriod;  // rewards for period AFTER exit
}
每个比较条件都要进行的思考测试

对每个 if (A > B),都问自己:“当 A == B 时会发生什么?”结果是否正确?

需要检查的 6 个边界位置
  1. 周期/纪元边界:周期结束时,> 与 >= 的区别
  2. 基于时间的锁:当 block.timestamp == deadline 时,是锁定还是解锁?
  3. 循环终止条件:使用 > 还是 >= 的 break
  4. 数组索引边界:i <= array.length(应为 i < array.length)
  5. 数量/余额边界:>= amount 是否允许精确全额提款?
  6. 舍入/精度:是否存在某种输入会导致应为非零的输出变为 0?
Grep 模式
# Boundaries in comparisons
grep -rn "Period\|Epoch\|Round\|Deadline\|period\|epoch\|deadline" contracts/ -A3 | grep "[<>][^=]"

# Loop breaks
grep -rn "\bbreak\b" contracts/ -B10

# Off-by-one in array access
grep -rn "\.length\s*-\s*1\|i\s*<=\s*.*\.length\b" contracts/

5. 预言机/价格操纵

占所有报告的 12%。单笔最高奖金。Mango 损失 1.17 亿美元,Curve 损失 7000 万美元。

漏洞 A:缺少数据过期检查(最常见)
// VULNERABLE:
(, int256 price,,,) = priceFeed.latestRoundData();
return uint256(price);  // If Chainlink node goes down, stale price returned indefinitely

// CORRECT:
(, int256 price,, uint256 updatedAt,) = priceFeed.latestRoundData();
require(block.timestamp - updatedAt <= MAX_PRICE_AGE, "Stale price");
require(price > 0, "Invalid price");
漏洞 B:缺少置信区间检查(Pyth)
// VULNERABLE:
PythStructs.Price memory p = pyth.getPriceUnsafe(priceFeed);
return p.price;  // ignores p.conf (confidence interval)

// CORRECT:
require(p.conf * 10 <= uint64(p.price), "Price too uncertain");
// conf > 10% of price = untrustworthy
漏洞 C:TWAP 时间窗口过短(可被闪电贷操纵)
// VULNERABLE: 60-second TWAP
uint32[] memory secondsAgos = new uint32[](2);
secondsAgos[0] = 60; secondsAgos[1] = 0;
// Flash loan can shift price for entire 60s window

// CORRECT: 1800s minimum TWAP (30 min)
漏洞 D:单一来源预言机
// VULNERABLE: only Uniswap spot price
uint price = getUniswapSpotPrice(token);  // flash loan manipulatable

// CORRECT: Chainlink primary, Uniswap TWAP as fallback, require close agreement
Grep 模式
# Missing staleness check
grep -rn "latestRoundData" contracts/ -A5 | grep -v "updatedAt\|timestamp"

# Pyth price usage — confidence interval checked?
grep -rn "getPriceUnsafe\|getPrice\b" contracts/ -A8 | grep -v "conf\|confidence"

# TWAP windows — short TWAP flag
grep -rn "secondsAgo\|TWAP\|cardinality" contracts/ -A5

6. ERC4626 金库攻击

汇率操纵(近乎空置的金库)
// VULNERABLE — first depositor attack:
// 1. Attacker deposits 1 wei → gets 1 share
// 2. Attacker donates large amount directly (transfer, not deposit)
// 3. Exchange rate: 1 share = (1 + donation) assets
// 4. Victim deposits → rounds down to 0 shares → free donation to attacker

// CORRECT: virtual shares (OpenZeppelin v4.9+)
function _decimalsOffset() internal view virtual override returns (uint8) {
    return 9;  // add 1e9 virtual shares + assets to prevent manipulation
}
ERC4626 转账(转移份额,但不转移质押/锁定记录)
// VULNERABLE: shares transferred, but lock records stay with original owner
// → shares stuck, can't redeem → permanent freeze (Belong pattern)
function transfer(address to, uint256 amount) external override {
    _transfer(msg.sender, to, amount);  // moves shares
    // MISSING: transfer lock record from msg.sender to `to`
}
Grep 模式
grep -rn "function transfer\|function transferFrom" contracts/ -A15
grep -rn "function deposit\|function mint\|function withdraw\|function redeem" contracts/ -A10

7. 重入攻击

2016 年至今。CEI 模式可以防止此类攻击,但 DeFi 中仍时有发现。

变体
  • 单函数:攻击者在状态更新前重新进入同一函数
  • 跨函数:攻击者使用过期状态重新进入同级函数
  • 跨合约:通过回调重新进入另一个协议
  • 只读:重新进入返回过期数据的 view 函数,供攻击者使用
根本原因模式
// VULNERABLE (effects after interaction):
function withdraw(uint256 amount) external {
    require(balances[msg.sender] >= amount);
    (bool success,) = msg.sender.call{value: amount}("");  // INTERACTION first
    require(success);
    balances[msg.sender] -= amount;  // EFFECT after → reentrancy window
}

// CORRECT (CEI — Checks, Effects, Interactions):
function withdraw(uint256 amount) external {
    require(balances[msg.sender] >= amount);  // CHECK
    balances[msg.sender] -= amount;            // EFFECT
    (bool success,) = msg.sender.call{value: amount}("");  // INTERACTION last
    require(success);
}
Grep 模式
# External calls before state updates
grep -rn "\.call{value\|safeTransfer\|transfer(" contracts/ -B10 | grep -v "require\|revert"

# Missing nonReentrant modifier on critical functions
grep -rn "function withdraw\|function redeem\|function claim" contracts/ -A2 | grep -v "nonReentrant"

# Storage slot for reentrancy guard
grep -rn "nonReentrant\|ReentrancyGuard\|_notEntered" contracts/

8. 闪电贷攻击

通过闪电贷操纵预言机
// Attack flow:
// 1. Borrow $100M from Aave flash loan
// 2. Dump token in Uniswap pool → crash spot price
// 3. Protocol reads Uniswap spot → undercollateralized loans accepted
// 4. Borrow max against cheap collateral
// 5. Repay flash loan, keep profits
价格预言机合理性检查(检查要点)
grep -rn "getReserves\|getAmountsOut\|slot0\b" contracts/ -A5
# spot price from reserves = manipulatable with flash loan
# slot0 = Uniswap V3 spot price = manipulatable

9. 签名重放

缺少 Nonce
// VULNERABLE:
function permit(address owner, address spender, uint256 value,
                uint256 deadline, uint8 v, bytes32 r, bytes32 s) external {
    bytes32 hash = keccak256(abi.encodePacked(owner, spender, value, deadline));
    // MISSING: nonce not included → same signature usable multiple times
    require(ecrecover(hash, v, r, s) == owner);
}
缺少 Chain ID
// VULNERABLE: signature valid on mainnet AND testnet AND all forks
bytes32 hash = keccak256(abi.encodePacked(params));
// MISSING: block.chainid not in hash → works on any chain
Grep 模式
grep -rn "ecrecover\|ECDSA\.recover" contracts/ -B20
# Check: does the signed hash include nonce + chainId + contract address?

grep -rn "nonce\|_nonces\|nonces\[" contracts/

10. 代理/升级问题

存储冲突
// Implementation and proxy share storage layout
// Proxy slot 0: _owner
// Implementation slot 0: _initialized
// → writing to _initialized overwrites _owner
未初始化的实现合约
// If implementation can be initialized directly → anyone becomes owner of implementation
// Attack: call initialize() on implementation contract → call upgradeTo() → replace logic
对用户控制的地址执行 delegatecall
function execute(address target, bytes calldata data) external onlyOwner {
    target.delegatecall(data);  // target is validated, but what if owner is compromised?
}
Grep 模式
# UUPS initialization protection
grep -rn "function initialize\b\|_disableInitializers\|initializer" contracts/

# Delegate call
grep -rn "delegatecall\b" contracts/ -B3 -A5

# Storage layout — proxy uses EIP-1967 slots?
grep -rn "0x360894\|EIP1967\|_IMPLEMENTATION_SLOT" contracts/

FOUNDRY POC 模板

// SPDX-License-Identifier: MIT
pragma solidity ^0.8.0;

import "forge-std/Test.sol";
import "../src/VulnerableContract.sol";

contract ExploitTest is Test {
    VulnerableContract target;
    address attacker = makeAddr("attacker");
    address victim = makeAddr("victim");

    function setUp() public {
        // Fork mainnet at specific block
        vm.createSelectFork("mainnet", BLOCK_NUMBER);

        // Deploy or load target
        target = VulnerableContract(TARGET_ADDRESS);

        // Fund accounts
        deal(address(token), attacker, INITIAL_BALANCE);
        deal(address(token), victim, VICTIM_BALANCE);
    }

    function test_exploit() public {
        console.log("Attacker balance before:", token.balanceOf(attacker));

        vm.startPrank(attacker);

        // Step 1: Setup conditions
        // Step 2: Execute exploit
        // Step 3: Verify impact

        vm.stopPrank();

        console.log("Attacker balance after:", token.balanceOf(attacker));
        assertGt(token.balanceOf(attacker), INITIAL_BALANCE, "Exploit failed");
    }
}
Foundry 关键作弊码
vm.prank(address)           // next call from address
vm.startPrank(address)      // all calls from address until stopPrank()
vm.deal(address, amount)    // set ETH balance
deal(token, address, amount) // set ERC20 balance
vm.warp(timestamp)          // set block.timestamp
vm.roll(blockNumber)        // set block.number
vm.createSelectFork("mainnet", blockNumber)  // fork mainnet
vm.expectRevert(bytes)      // next call should revert
vm.label(address, "name")   // label for trace output
vm.assume(condition)        // fuzz: discard inputs where false
运行测试
# Run specific test
forge test --match-test test_exploit -vvvv

# Run with fork
forge test --match-test test_exploit -vvvv --fork-url $MAINNET_RPC

# Gas report
forge test --gas-report

# Coverage
forge coverage --report summary

验证

  1. Solana 工具——确认 Anchor/SPL 工具可用:
    which anchor 2>/dev/null && echo "PASS: anchor CLI found" || echo "NOTE: anchor not installed"
    which solana 2>/dev/null && echo "PASS: solana CLI found" || echo "NOTE: solana CLI not installed"
    
  2. 常见 Solana 漏洞类别——确认已记录关键类别:
    grep -q "account confusion\|signer check\|CPI\|PDA\|bump seed" SKILL.md && echo "PASS: Solana-specific vuln classes present" || echo "FAIL"
    

所有测试均可验证 Web3 审计准备情况。


注意事项

  • 混淆 Solana 与 EVM——Solana 的编程模型(Rust、BPF)与 EVM(Solidity、EVM 字节码)完全不同。不要混用技术。
  • 非 EVM 链上的重入——Solana 运行时会在一个区块内按顺序处理交易。跨程序调用(CPI)重入与 EVM 重入不同。
  • Solana 账户混淆——Solana 的账户模型要求显式传递账户。缺少签名者检查和账户验证是 Solana 的主要漏洞类别。
  • 任意 CPI 漏洞——将用户控制的程序 ID 传递给 invoke() 或 invoke_signed(),会允许调用任意程序。
  • 误用 PDA(程序派生地址)——未进行适当种子验证的 PDA 可能被伪造。未经类型检查、来自用户输入的种子很危险。

相关技能与链

  • meme-coin-audit——当目标是 meme 币/SPL 代币,而非 DeFi 协议时使用。工作流原语:审计前的终止信号有所不同——本技能的“TVL < $500K 时跳过”不适用于 meme 币,因为 rug 检查(铸造权限、冻结权限、LP 锁定)就是全部审计内容;此时应改用 meme-coin-audit。
  • triage-validation——当合约发现已准备好提交至 Immunefi 时使用。工作流原语:Immunefi 有自己的报告格式,但 triage-validation 中经过影响验证、覆盖整个链路的严谨流程仍然适用;提交前,请对 Foundry PoC 执行 7Q 检查。
  • report-writing——撰写 Immunefi 报告正文时使用。工作流原语:report-writing 的 Immunefi 模板(包含 Foundry PoC、根本原因代码片段、量化的经济影响)是本技能发现内容所填充的正文骨架。
  • offensive-osint——审计协议的链下攻击面(前端、管理 API、RPC 网关)时使用。工作流原语:链上审计由本技能负责;协议中的任何 web2 组件(web-frontend、管理面板、索引器 API)都应交由 offensive-osint 进行侦察。
  • bb-methodology——决定是否开展深入审计时使用。工作流原语:bb-methodology 的 PART 0 用于确认项目类型(web3 漏洞赏金/私人审计/智能合约审查);本技能的审计前终止信号取代该项目类型的标准评分标准。

操作说明

基于参与项目经验,并针对 2026 年对 vendored 基础内容所做的补充。 来自真实授权项目的经验,以及对本仓库 31+ 个技能领域实时测试进行的第 2 阶段验证。上游内容介绍了「是什么」; 本层介绍了「何时有效,何时无效」。

2026 年仍有收益的漏洞类别

闪电贷攻击仍是 Immunefi 上收益最高的攻击类型之一(按赏金计算,2024—2026 年排名前 5)。其经济原语——借入 5,000 万美元、操纵价格预言机、抽干资金池、偿还贷款——不断重现,因为新协议持续上线,并假设可组合性在闪电贷造成失衡时仍然成立。

重入攻击仍然有利可图,因为新协议持续上线,并使用 ERC-777/钩子/回调。不要以为这类漏洞已经绝迹——2023—2025 年的已支付漏洞库中,包含 40 多个针对采用了 Checks-Effects-Interactions 模式之后的代码库的重入漏洞(跨函数重入,以及通过在状态变更过程中调用 view 函数实现的只读重入)。

预言机操纵:仍然有丰厚回报,但难度更高。如今大多数项目都使用 Chainlink 价格馈送;攻击目标是大多数项目也使用的次级预言机(来自低流动性 Uniswap V2 交易对的 TWAP、协议自身的内部预言机,或过时的备用路径)。审计故障转移链,而不只是主馈送。

自 vendored 内容编写以来的新变化
  • EIP-1153(瞬态存储)——于 2024 年引入。出现了新的重入漏洞类型:在同一笔交易中缓存的瞬态存储读取结果可能与持久化存储失步。审计任何 tload/tstore 用法,检查外部调用之后的读取。
  • EIP-7702(2025 年 Pectra 硬分叉)——新增了 EOA 升级为智能账户的功能。重新委托会带来类似 ATO 的新攻击原语:EOA 一次性签名后可委托给攻击者控制的合约,随后攻击者便可跨委托重放签名。
  • 账户抽象(ERC-4337 bundler)——Paymaster 赞助滥用和 bundler 骚扰。未严格执行发送者允许列表的 Paymaster 合约,首次调用时就可能被耗尽资金。
  • ZK-rollup 桥接漏洞——跨 rollup 重放证明、链下证明者遭入侵,以及排序器审查导致的强制纳入边界情况。
  • LST/LRT 脱锚动态——流动性质押和流动性再质押代币在亏损情况下仍假定保持 1:1 锚定;预言机假定锚定,市场反映脱锚,清算逻辑随之失效。
2026 年工具栈

Foundry 仍是测试框架。使用 forge test --gas-report --debug 进行不变量测试;使用 forge fuzz 进行基于属性的测试;使用 forge inspect 审计存储布局。结合 Slither 和 Echidna 进行静态分析与模糊测试。使用 Mythril 对较小的合约进行符号执行。使用 tenderly.co 进行分叉和模拟(这是复现主网状态下攻击体验最佳的工具)。

对于 Solana:使用 anchor 框架、sealevel-attacks 漏洞库(由 anchor 维护者整理的 PoC)和 soteria-sec/sec3 扫描器。对于 Move(Aptos、Sui):使用 move-prover 和 aptos-cli aptos move test。

对于跨链项目:hyperlane 和 LayerZero 都有审计工具仓库;桥接漏洞需要模拟两端,而不只是其中一端。

预审阶段的止损信号何时重要

TVL 低于 50 万美元的项目不值得花时间审计,除非赏金最低金额很高。若审计公司已审计过,投资回报率就偏低,除非你能发现其遗漏的问题——查看审计报告中的范围排除部分,了解他们明确未审计的内容(预言机、治理、链下组件、前端、管理员路径)。

多签签署者超过 5 人且 timelock 超过 48 小时,意味着 rug-pull 风险较低;如果你的发现依赖于团队恶意这一假设,那么其影响较低,而且很可能会根据 Immunefi 的「中心化风险」排除条款被判定为范围外。阅读项目计划说明——大多数 Immunefi 项目都会明确降低或拒绝那些假设管理员恶意的发现。

报告规范

Immunefi 要求提供 Foundry PoC。未提交 PoC 的报告会被自动拒绝。需要手动设置(“先部署这个,再调用那个”)的 PoC 通常会被降级——PoC 应当通过一次 forge test 调用证明影响,并使用明确的 assertEq 断言被清空的余额、铸造的代币或遭破坏的状态。

严重性声明必须严格遵循 Immunefi 的严重性矩阵;不要自行编造严重性等级。矩阵根据 TVL 的直接经济损失百分比划分等级——针对 50 万美元协议的 Critical,与针对 5 亿美元协议的 Critical,奖金不同。声明 Critical 前,请先阅读该计划的具体严重性分配标准。

评论

支持 Markdown