Notes ahead of planning to be a perfect Web3 Security Auditor:
- Analyze loops and arrays to detect DoS vulnerabilities.
- Analyze the (CEI) Check-Effects-Interactions for
Rentrancy Vulnerabilities. - There's a GitHub Repo maintained by Pascal (legend) that catalogues re-entrancy attacks which have occurred, good to have the case studies init.
Rentrancy Vulnerability Case Study:https://medium.com/@zhongqiangc/smart-contract-reentrancy-thedao-f2da1d25180c
- Have a perfect auditting IDE (VS Code or VS Codium)
- Understand the protocol best practices.
- Understand the current state of Web3 security.
- Understand solidity auditting tools such as Slither, Mythril
- Understand Fuzzing & Invariants
- Understand the format of smart contracts such as ERC20's, ERC721's
- Understand smart contract's ABI's
- Understand upgradable contracts
- Understand self destruction
- Phases of a security review:
[Initial Review]
1. Scoping
- Always do security reviews/audits on
dev isolated environmentsusingdocker containers. - In the project
README.mdfile, remember and check for the things we're looking for:
- About
- Setup
- Scope
- Compatibilities
- Roles - role in the project and their privileges.
- Known Issues
- Observe the
makefile and see what it has. If possible run it. - About the project - Knowledge about the project and its business logic is crucial. This can be attained from the project documentation.
- Stats of the project - Information about the size of the codebase, how many lines of code are in scope, and its complexity are incredibly vital.
sudo apt install cloc# Debian, Ubuntu installation.
cloc ./src/using cloc alongside the folder to count lines of code.
- Using
solidity metricstool for scoping and understanfing the application logic. - Using
solidity metricstool understand how functions operate and how calls are made. This helps in finding attack vectors of the smart contract. - Using
solidity visual developertool for scoping. This tool provides syntax highlighting in your code based on variable types - Setup - how to build and test the project, which frameworks they've used etc.
- Review Scope (inscope and out of scope).
- Compatibilities - Information about the solidity version the client is using, the chains they plan on working with, and the tokens they will be integrating.
- Roles - This entails understanding the different roles and powers within the system and detailing what the different actors should and shouldn't be able to do.
- Known issues - Understanding existing vulnerabilities and bugs which are already being considered/fixed. Now focus on the hidden issues.
2. Reconnaissance
- Read the docs and have a general understanding of what the protocol does (you can create
Notes.mdfile and have custom notes on what the protocol does). - Use
solidity metricstool to read and understand the code and what it actually does. - Pay special attention to the functions marked
publicorexternal. Especially those whichmodify stateor arepayable. These are going to be certain potential attack vectors. - Have deep and closer looks at the
NatSpecsandComments. - Scoping Out The Files.
- When reading the code, start from the main entry of the protocol.
- Immutable variables such as
i_entranceFee, ENTRANCE_FEEshould be initialised in the constructor. - Run
static analysis toolssuch asslither - $ slither.for solidity andaderynfor rust projects/protocols. - Create a file named
Noted.mdand have notes concerningAbout the project in my own wordsand also theAttack vectors of the projct. - Use tags for infomational issues upto the vulnerability issues such as
@audit - ifor informational,@audit - lowfor low issues,@audit - mediumfor medium issues and@audit - highfor high issues. - Make notes about the project code such as
s_owneris a storage variable. Do the same for other parts of the code such asevents,constructore.t.c - Enure you read comments that have been coded alongside the project code.
- Check if the tests cover all the logic and functions of the protocol. Tests should also check what the functional logic should not doo such as (function for owner setting password -- we should have a test that checks in non-owners too can set passwords).
- Run
forge coverage, and if perfomance is poor, then there is a high chance of finding more security vulnerabilities.
3. Vulnerability identification
- Use all tools and tactics here to detect the vulnerabilities.
- Keeping close with the recon process will help in detecting vulnerabilities.
- Create a file named
findings.mdthat will have quick documentation and summaries of the detected vulnerabilities. Static Analysisby use of tools such as in solidity -Slitherand in rustAderyn.- Slither command
slither .- this runs static analysis in the whole project. - Aderyn command
aderyn .- this runs static analysis in the whole project (you can run it on a solidity project too). - Slither will automatically detect if the project is a Hardhat, Foundry, Dapp or Brownie framework and compile things accordingly.
4. Reporting
- Title must be (
root cause+impact) such as:Storing the password on-chain makes it visible to anyone, and no longer private - Create a cool description that describes the vulnerability, vulnerable variables. Always mention the contract that the vulnerable variables exist such as
PasswordStore::s_password. Below is an example of a robust description:
**Description:** All data stored on chain is public and visible to anyone. The `PasswordStore::s_password` variable is intended to be hidden and only accessible by the owner through the `PasswordStore::getPassword` function.
I show one such method of reading any data off chain below.- Impact should be clear and real such as:
**Impact:** Anyone is able to read the private password, severely breaking the functionality of the protocol.Proof Of ConceptorProof Of Codeproves that the issue submitted is a real issue. Quite advantageous on competetive audits and bug bounty programs.- Create a working
Proof Of Conceptwith steps and document it on the report. You can attach screenshots and videos if possible. - For the POC, one can just add the valid fuzz
testcreated for the vulnerability. - Use AI to polish your reports. In this, you need a better prompt such as:
The following is a markdown write-up of a finding in a smart contract codebase, can you help me make sure it is grammatically correct and formatted nicely?
---
PASTE-REPORT HERE
---- Severity rating of the vulnerability.
- To get severity of the vulnerability think of it in terms of user experience - how pissed off would users be if an attack happened?
- This is how severity and titles are labelled:
### [H-1] Storing the password on-chain makes it visible to anyone and no longer private
### [H-2] `PasswordStore::setPassword` has no access controls, meaning a non-owner could change the password
### [I-1] The 'PasswordStore::getPassword` natspec indicates a parameter that doesn't exist, causing the natspec to be incorrect- Timeboxing redo another review on the protocol incase you might have missed anything.
- Example of a perfect report:
Storing the password on-chain makes it visible to anyone (Click to expand)
Description:
- All data stored on chain is public and visible to anyone. The
PasswordStore::s_passwordvariable is intended to be hidden and only accessible by the owner through thePasswordStore::getPasswordfunction. - I show one such method of reading any data off chain below.
Impact:
- Anyone is able to read the private password, severely breaking the functionality of the protocol.
Proof of Concept: The below test case shows how anyone could read the password directly from the blockchain. We use foundry's cast tool to read directly from the storage of the contract, without being the owner.
- Create a locally running chain
make anvil- Deploy the contract to the chain
make deploy- Run the storage tool
- We use 1 because that's the storage slot of s_password in the contract.
cast storage <ADDRESS_HERE> 1 --rpc-url http://127.0.0.1:8545You'll get an output that looks like this:
0x6d7950617373776f726400000000000000000000000000000000000000000014
You can then parse that hex to a string with:
cast parse-bytes32-string 0x6d7950617373776f726400000000000000000000000000000000000000000014And get an output of:
myPassword
Recommended Mitigation:
- Due to this, the overall architecture of the contract should be rethought. One could encrypt the password off-chain, and then store the encrypted password on-chain. This would require the user to remember another password off-chain to decrypt the stored password. However, you're also likely want to remove the view function as you wouldn't want the user to accidentally send a transaction with this decryption key.
-
To practice on several exploits use the sc-exploits-minimized repo as shown in the image below:

-
The sc-exploits-minimized repo also has vulnerability based CTFs to solve and improve exploitation skills.