When I first started auditing, my approach was extremely standardized. I audited each contract line by line, understanding the business logic, function by function.
At this stage, I was focused on grasping what each function did and how it fit into the larger functionality. However, this line-by-line approach, while thorough, had limitations:
Missed Vulnerabilities:
Some bugs, especially complex ones involving cross-functional or state-based logic, can simply not be found by using this approach only.
Difficulty Seeing the Big Picture: Focusing so closely on individual lines of code made it challenging to understand the contract’s broader design or how different parts interacted.
At this stage, I was building foundational skills, understanding syntax, structure, and the logic behind various functions, but I hadn’t yet developed a method to catch some of the more complex or nuanced vulnerabilities.
It was an extreme hard process during this phase because the resources how to learn solidity (let alone auditing) were extremely limited (I bought some courses on Udemy back then)
Second Step: Introducing Function Jumping and State Differentiation
In my second step, I adapted my process to address the limitations of pure line-by-line auditing. I began to jump between functions, tracking how different functions connected and interacted with each other. This shift helped me get a better grasp on state management within contracts:
Better Contextual Awareness:
By understanding the interconnections between functions, I was able to identify vulnerabilities in the transitions between contract states.
Functionality-Based Auditing:
Instead of focusing on individual lines in isolation, I started viewing functions as part of a broader context. This enabled me to uncover logic issues that occur when functions are used together or in specific sequences.
This approach helped me catch more bugs and improved my ability to analyze complex function interactions. At this point, I had developed a more holistic view of the code but the ability to efficiently spot game-theoretical issues or vulnerabilities in contract states was still not perfect.
Third Step: Initial Assessment Through State Separation
During the third step, I began my audits with an initial assessment based on contract states. With more experience, I found that I could identify potential weaknesses simply by mapping out the different states and interactions:
Preliminary Bug Identification:
During this initial assessment, I could already find bugs simply by categorizing and understanding contract states. The process of separating and analyzing these states made many vulnerabilities clear right from the start.
Pattern Recognition and Sensitivity:
Experience had taught me to recognize patterns and identify areas that were likely to contain vulnerabilities. Certain coding patterns or state transitions became red flags, and I intuitively knew where to look. This must not be mixed up with pattern matching which most auditors do these days.
This shift in focus allowed me to understand the contract’s dynamics more deeply, making it easier to uncover vulnerabilities in the broader logic rather than just in isolated functions. At this stage, I started uncovering more sophisticated bugs and edge cases, especially those related to state transitions and variable sensitivity.
Fourth Step: Freestyle Auditing and Intuition-Driven Leads
During the fourth step, my approach had become highly intuition-driven. I no longer felt the need to start at the beginning of a contract or follow a strict line-by-line order. Instead, I started randomly within the architecture and spent the first few days exploring the codebase freestyle:
Lead-Based Auditing:
Instead of systematically working through functions, I would list potential leads, following my intuition to areas that I suspected might have vulnerabilities. Interestingly, the intuition was by that time already so great that I can find multiple leads / potential leads within the first few minutes.
Deep Architectural Understanding:
This freestyle approach gave me a great understanding of the contract’s architecture. I began to uncover game-theoretical scenarios and complex vulnerabilities that might have been hidden in conventional audits.
High Success Rate of Intuition:
At this point, my intuition had become a critical tool. Years of experience meant that I could sense which areas of the code were likely to contain vulnerabilities. I would often uncover significant issues based purely on this intuition.
This evolution of my approach meant that I could assess not only the security of individual functions but the security of the entire protocol’s structure and intent, including very sophisticated issues which were hard to explain “how I found them”.
I reached a point where I was confident enough to say that with sufficient carefulness and time, I am able to uncover around 95% of all issues. This has proven itself again and again when participating in team audits.
This does not mean that my auditing approach these days is purely based on intuition and freestyle auditing. It's only one part of many parts of my methodology for a full audit.
Reflection: How Experience Shapes Auditing Approaches
Over the years, my auditing approach transformed from a detailed, line-by-line process to one driven by intuition and architectural understanding. As I gained experience, I learned that while foundational skills and systematic approaches are crucial in the beginning, intuition and a deep understanding of contract dynamics become invaluable tools for discovering the most sophisticated vulnerabilities.
As knowledge and experience grow, an auditor’s intuition becomes one of the most reliable resources. This intuition enables us to see beyond the syntax and dive into the underlying logic and strategy of the code, revealing vulnerabilities that are nearly invisible in standard audit. There are some really great issues which other team members couldnt even reproduce when I told them exactly where to look for and what to look for, simply because reproducing the bug needed a few different, consecutive state transitions before it became visible.