Audit report writing for smart contract vulnerabilities. Triggers on weasel report, weasel write up, or weasel document.
Expert in formatting security findings as professional audit reports.
Do NOT run Weasel analysis - user already found the bug!
ALWAYS write report to a file. NEVER output report content to terminal.
findings/
āāā H-01-reentrancy-in-withdraw.md
āāā H-02-access-control-bypass.md
āāā M-01-unchecked-return-value.md
āāā ...
Pattern: <SEVERITY>-<NUMBER>-<short-description>.md
# Create file
findings/H-01-reentrancy-in-withdraw.md
Ask user: "Create separate files per finding, or one combined report?"
findings/H-01-xxx.md, findings/M-01-yyy.md (better for submission)findings/audit-report.md (all findings in one file)Confirm to user:
Report written: findings/H-01-reentrancy-in-withdraw.md
| Rationalization | Why It's Wrong |
|---|---|
| "I'll output to terminal so user can review first" | User can review the file. Terminal output gets lost. |
| "It's just one finding, doesn't need a file" | Even one finding needs a file for submission/tracking. |
| "User didn't specify a path" | Use findings/ directory by default. |
| "I'll paste the full PoC for completeness" | Link is complete. Full code bloats report. |
| "User's custom format had ## POC section" | Custom format doesn't mean paste code. Still use link. |
## [SEVERITY-XX] Title That Describes The Impact
### Summary
One sentence: what's broken and what's the impact.
### Vulnerability Detail
- What the vulnerability is
- How it occurs
- Why it's a problem
### Impact
What an attacker can achieve (fund loss, DoS, corruption).
### Code Snippet
`path/to/file.sol#L123-L130`
\`\`\`solidity
function withdraw(uint256 amount) external {
(bool success, ) = msg.sender.call{value: amount}(""); // @audit reentrancy
balances[msg.sender] -= amount;
}
\`\`\`
### Recommendation
\`\`\`solidity
function withdraw(uint256 amount) external nonReentrant {
balances[msg.sender] -= amount;
(bool success, ) = msg.sender.call{value: amount}("");
}
\`\`\`
### PoC
See: `test/Contract.t.sol::test_VulnName_PoC`
Default: Link only, not full code.
## PoC
See: `test/Vault.t.sol::test_Reentrancy_PoC`
Why link-only by default:
Exception: Include inline PoC only if:
Good: Specific, describes impact
withdraw() allows draining of user funds"setFee() allows anyone to set 100% fee"Bad: Vague
Number by severity: H-01, H-02, M-01, M-02, etc. Order: severity first, then by location.