3 of 3 instructions driven to both success and failure
Attack classes tried20 / 20
7 of 7 classes that apply to this program
Real state5 / 10
Synthetic accounts built from the IDL
Effort10 / 10
Share of the planned run completed
What sets the cap
CRITICAL2 proven, this sets the capcap 20
HIGHNone provencap 45
MEDIUMNone provencap 70
LOWNone provencap 90
Score is the lower of Depth and the cap from the worst proven finding. Leads never count.
2 proven findings
CRITICAL
Anyone can re-run initialize, take over the account, then withdraw its funds
F1
initialize does not check that the account is new. The attacker ran it again on an account the owner had already set up and wrote their own key in as the authority, then called withdraw and took 1 SOL.
The attack, in order
initialize by the owner, setup
initialize by the attacker
withdraw (1000000000) by the attacker
Account
Before
After
Program account (vault)
5.0009 SOL
4.0009 SOL
Attacker
10 SOL
10 SOL
Attacker's wallet
0 SOL
1 SOL
Fix: Refuse to initialize an account that already holds data (check the discriminator, or use Anchor's init constraint).
Program Ba9KvV1PMnLu37UT9R3XVQ26AYyvQ6kq5j83otRAkkyt invoke [1]
Program Ba9KvV1PMnLu37UT9R3XVQ26AYyvQ6kq5j83otRAkkyt consumed 794 of 200000 compute units
Program Ba9KvV1PMnLu37UT9R3XVQ26AYyvQ6kq5j83otRAkkyt success
Replay it locally with the report JSON: clone github.com/Verafyai/fuzzy, then npm run fuzzy -- replay report.json F1 --program your_program.so --idl idl.json
CRITICAL
Anyone can call withdraw without authority's signature and take funds
F2
withdraw never checks that authority signed. The attacker named the authority without their signature and the transaction succeeded, moving 1 SOL to the attacker.
The attack, in order
initialize by the owner, setup
withdraw (1000000000) by the attacker
Account
Before
After
Program account (vault)
5.0009 SOL
4.0009 SOL
Attacker's wallet
0 SOL
1 SOL
Attacker
10 SOL
10 SOL
Fix: Require authority to be a signer (in Anchor, Signer<'info>).
Program Ba9KvV1PMnLu37UT9R3XVQ26AYyvQ6kq5j83otRAkkyt invoke [1]
Program Ba9KvV1PMnLu37UT9R3XVQ26AYyvQ6kq5j83otRAkkyt consumed 796 of 200000 compute units
Program Ba9KvV1PMnLu37UT9R3XVQ26AYyvQ6kq5j83otRAkkyt success
Replay it locally with the report JSON: clone github.com/Verafyai/fuzzy, then npm run fuzzy -- replay report.json F2 --program your_program.so --idl idl.json
1 lead checked and not counted
ping accepts a fake vault.It accepted an account the program does not own, but changed nothing, so it is not counted.
Attack classes
Missing signer checkbroke it
Missing owner checkheld
Account substitutionheld
PDA seed collisiondoes not apply
Arithmetic overflowheld
Close, then reusedoes not apply
Unchecked CPI targetdoes not apply
Unchecked mint or authoritydoes not apply
Lamport drainingheld
Reinitializationbroke it
Price manipulationdoes not apply
Compute exhaustionheld
About this run
Every finding was reproduced in LiteSVM with the transaction attached. Leads were tried and did not break anything; they never count toward the score.
Branch coverage is not measured yet, so it adds 0 of 40 to Depth. With synthetic accounts, that caps any score from this engine version at 55.
Accounts are synthetic, built from the IDL.
Theft is measured in SOL. Token balances are not yet part of the proof, so token-only exploits show up as leads at most.