7 Years, 1400 Audits Later - Here’s What We Learned
Web3 security is a battlefield.
After seven years of auditing over 1,400 projects and reviewing more than a million lines of code, we at QuillAudits have learned a thing or two about keeping blockchain ecosystems safe.
Everything we learned throughout the last 7 years, we will teach you in this one blog.
Our experience spans not just smart contract auditing but also blockchain forensics, on-chain monitoring, and real-time threat detection.
Here are 10 essential tips for auditors and security researchers navigating the ever-evolving Web3 landscape.
1. Security Is an Ongoing Process, Not a One-Time Event
One of the most common yet dangerous misconceptions we’ve encountered in our 7 years of auditing is the belief that a single audit guarantees perpetual security.
Too many projects treat audits as a checkbox activity—something to be done once before launch and then forgotten.
This mindset has led to disastrous consequences, with multiple projects suffering exploits despite passing an audit.
So, why does this happen?
1.1 Code Evolves, and So Do Threats
The blockchain space is highly dynamic. A smart contract that was deemed secure at one point might become vulnerable due to:
- Many protocols introduce upgrades, but even a minor change in logic can introduce various attack vectors.
- A once-secure protocol might later integrate with another dApp, DEX, or bridge, exposing it to new risks.
- A previously secure function might become unsafe due to updates in the underlying blockchain, compiler, or dependencies.
A classic example is the DeFi space, where protocols interact with each other constantly.
A project might pass an audit, but if it later integrates with a vulnerable lending protocol or a compromised price oracle, it inherits those risks.
1.2 Attackers are Always Evolving
Blockchain security isn’t just about identifying existing threats—it’s about anticipating future ones.
Attackers are relentless, always looking for new loopholes.
Even if your project was secure when launched, emerging attack vectors (such as new forms of reentrancy, oracle manipulation, or MEV-based exploits) could break your defenses.
For instance, in the past year alone, we’ve seen:
- More sophisticated flash loan attacks leveraging multiple protocols.
- Novel oracle exploits affecting DeFi platforms.
- MEV-based front-running and sandwich attacks increasing significantly.
If a project is not continuously reassessing its security, it’s only a matter of time before attackers find a way in.
1.3 Audits Are Just One Layer of Defense
A security audit is a critical step, but it should never be the only line of defense. Projects need to adopt a multi-layered security approach that includes:
- One audit isn’t enough, especially if changes are made post-audit. We’ve seen cases where a project was audited, made last-minute changes, and then got exploited because those changes weren’t reviewed.
- Implement real-time security monitoring tools that track anomalies, suspicious transactions, and unusual fund movements.
- White-hat hackers can catch vulnerabilities that even the best audits might miss. We always recommend launching a bounty program post-audit.
- Tools like Slither, Echidna, and fuzz testing should be part of the CI/CD pipeline to catch potential bugs early.
1.4 Incidents We’ve Seen Firsthand
We’ve witnessed projects that got audited, launched with full confidence, but still got exploited because they failed to consider security as an ongoing process.
- A well-known DeFi protocol was audited but later integrated with a newly launched lending protocol. That lending protocol had an oracle manipulation vulnerability, which led to an exploit draining millions.
- A DAO treasury suffered a loss because they updated governance rules post-audit, accidentally allowing a loophole that attackers exploited to siphon funds.
- A GameFi project was secure at launch but introduced an update to their reward system. The new update had unchecked arithmetic operations, leading to an inflation bug that attackers leveraged to mint unlimited tokens.
2. Understand the Business Logic Before the Code
One of the most overlooked yet critical aspects of auditing is understanding why a protocol works the way it does before analyzing how it is implemented in code.
Many auditors jump straight into identifying technical vulnerabilities—like reentrancy or overflows—without fully grasping the underlying business logic.
This approach often leads to missed vulnerabilities that arise not from syntax errors but from flawed economic design, governance mechanisms, or incentive structures.
2.1 Why Business Logic Matters More Than Just Code
Smart contracts are not just programs; they are autonomous financial instruments that manage assets, execute trades, distribute rewards, and enforce governance rules.
A single oversight in logic—such as a misconfigured liquidation mechanism, improper fee calculations, or unchecked withdrawal conditions—can lead to catastrophic failures, even if the code itself is syntactically correct.
2.2 Key Steps Before Diving Into the Code
Before reviewing a single line of code, auditors should map out the protocol’s core logic:
- Read the whitepaper and documentation
- Identify the core functionalities (lending, staking, swaps, governance).
- Understand how the protocol interacts with external dependencies (oracles, bridges, third-party protocols).
- Assess the intended incentive structures—who profits, who takes risks?
- Analyze the protocol’s economic design
- Is there a possibility of infinite minting or value dilution?
- Are liquidations, interest rates, or reward mechanisms manipulatable?
- Can users drain funds through unintended logic flows?
- Identify key actors and their privileges
- Who can upgrade contracts?
- Are admin roles centralized or governed by DAO voting?
- Could a malicious governance proposal take over the system?
Only once these aspects are fully understood should the actual line-by-line code review begin.
2.3 Common Business Logic Flaws We’ve Encountered
Here are some of the most dangerous business logic flaws we’ve seen over 1,400 audits:
- A protocol depended on a single, manipulatable price oracle, allowing attackers to distort asset prices and drain liquidity.
- A reward distribution mechanism had no upper limit, leading to unintended token inflation.
- A DAO’s governance system had vote delegation but failed to limit how many votes a single entity could accumulate, allowing a hostile takeover.
- A vault contract allowed users to withdraw funds before price updates, enabling them to game the system and siphon funds.
- A staking mechanism had no lock-in period, letting users stake and unstake within the same transaction to earn rewards infinitely.
2.4 Business Logic Auditing Best Practices
To avoid these issues, auditors must:
- Start every audit with a protocol walkthrough, discuss with developers, ask clarifying questions.
- think like an attacker: How could someone manipulate incentives for unfair advantage?
- Review past exploits in similar protocols—many business logic flaws are repeated across projects.
- Document unintended economic risks—sometimes, the logic works as coded but leads to long-term instability.
3. Simulate Real-World Attacks
A static code review is just the first layer of security.
The real challenge? Understanding how an attacker would actively exploit a protocol in the wild.
This is where penetration testing and adversarial simulations become essential. Over 1,400 audits, we’ve seen firsthand that many of the most devastating exploits weren’t due to basic coding errors but complex attack vectors that only surfaced during active testing.
3.1 Why Static Analysis Alone Isn’t Enough
Code audits focus on identifying logical errors, permission misconfigurations, and potential vulnerabilities. But attackers don’t just read code; they test, probe, and manipulate contracts in ways developers often don’t anticipate. Some of the biggest exploits in Web3 history have involved intricate multi-step attack strategies that no single line of code explicitly reveals.
For example:
- Flash loan exploits: A contract might seem secure, but introducing unlimited borrowing with no collateral opens up price manipulation attacks that can wipe out entire liquidity pools.
- MEV-based attacks: Even if a contract is properly coded, attackers can front-run, back-run, or sandwich transactions to extract unfair profits.
- Composability risks: A protocol that interacts with third-party DeFi applications might be vulnerable if those external contracts introduce unexpected behaviors.
3.2 How We Approach Adversarial Testing
We don’t just read the code—we attack it. Here’s how penetration testing in Web3 should be conducted:
Develop a Threat Model
- Identify critical contract functions (e.g., lending, borrowing, swapping).
- Map out who can interact with the contract and what actions they can take.
- Consider external dependencies—how does this contract rely on price oracles, bridges, or governance mechanisms?
Simulate Common Attack Vectors
- Flash Loan Attacks: Can an attacker borrow and return funds within a single block to manipulate prices or drain liquidity?
- Reentrancy Attacks: Does the contract make external calls before updating internal balances, allowing an attacker to loop transactions?
- MEV Exploits: Can transactions be reordered to create arbitrage opportunities that harm users?
- Oracle Manipulation: Does the contract rely on a price feed that could be spoofed or manipulated?
Run Automated and Manual Testing
- Use Foundry, Echidna, and Slither to generate fuzzing tests, simulating thousands of attack attempts.
- Manually execute transactions on testnets and local environments, mimicking real-world attackers.
- Deploy bots to simulate high-frequency trading strategies that could expose weaknesses.
Verify Post-Exploitation Scenarios
- If an attack is successful, trace how funds flow and determine whether an attacker could withdraw them.
- Check for emergency recovery mechanisms—can the protocol mitigate the damage once an exploit is triggered?
- Assess the impact of liquidity drains and whether they create systemic risks.
4. Forensics Mindset: Every Transaction Tells a Story
Security doesn’t stop at auditing. Once a protocol goes live, the real battlefield begins—and that’s where on-chain forensics becomes invaluable.
Every transaction on the blockchain leaves a footprint, and if you know what to look for, you can detect potential exploits before they happen or trace stolen funds in the aftermath of an attack.
At QuillAudits, our experience in on-chain monitoring and post-hack investigations has reinforced a crucial lesson: blockchain forensics isn’t just a reactive process—it’s a proactive one.
Developing a forensic mindset as an auditor allows you to spot patterns, recognize anomalies, and think one step ahead of attackers.
4.1 How a Forensics Mindset Strengthens Auditing
While traditional security audits focus on code correctness, a forensic approach examines how that code will interact with real-world blockchain activity.
Here’s why this perspective is critical:
Attackers Leave Clues Before Striking
- Exploits don’t always happen out of nowhere. Many attacks start with small, unusual transactions, such as testing contract behavior with low-value transactions or probing liquidity depths.
- Suspicious patterns, like a single address interacting with multiple unrelated protocols within a short time, often indicate wallet-draining bot activity or smart contract stress-testing by attackers.
Tracing Stolen Funds & Understanding Exploit Tactics
- Once an exploit occurs, hackers rarely cash out immediately. They first obfuscate their trail, using mixers, cross-chain bridges, or peeling techniques.
- Understanding how attackers move stolen funds (e.g., through Tornado Cash, Railgun, CEX deposits) allows for quicker response times and possible fund recovery efforts.
3. Detecting Money Laundering in DeFi
- Many DeFi protocols have become money laundering hubs for stolen funds. Attackers often use flash loans, decentralized exchanges, and lending platforms to mix illicit assets.
- Forensic analysis helps flag suspicious patterns early, aiding exchanges and law enforcement in freezing stolen assets before they vanish.
5. Trust but Verify - Even Official Libraries & Standards
Widely used libraries and standards, such as OpenZeppelin contracts and ERC token standards, provide a solid foundation, but assuming they are flawless is a dangerous mistake.
History has shown that even well-audited, battle-tested code can have subtle vulnerabilities, misconfigurations, or implementation risks—especially when used in unintended ways.
5.1 Why You Should Always Verify Imported Code
Past Vulnerabilities in "Safe" Contracts
- OpenZeppelin’s Own Fixes: Even OpenZeppelin has patched critical issues in its libraries over time. If you import without verification, you might be relying on outdated or vulnerable code.
- ERC-20's Approval Bug: The well-known ERC-20
approve()
function introduced double-spending risks when allowances were reset incorrectly, a flaw that persisted in many projects before mitigations like increaseAllowance()
were introduced.
Upgradeable Contracts Introduce Hidden Risks
- Storage Collisions: Many projects use OpenZeppelin’s Upgradeable Proxy pattern but fail to verify storage slot alignment, leading to unexpected data corruption.
- Admin Takeover Risks: Misconfigured upgradeable governance can lead to unauthorized upgrades or malicious contract takeovers.
Standards Define Intent, Not Implementation
- ERCs provide guidelines, not guarantees. Two projects implementing the same ERC might behave differently under edge cases, introducing unexpected vulnerabilities.
- Custom modifications to standard libraries often introduce hidden dependencies or breaking changes, making even "trusted" code risky.
5.2 What Should You Do Instead?
- Audit Every Imported Contract. Don’t just assume security because it’s from OpenZeppelin.
- Check for the Latest Version. Libraries evolve, and using outdated versions can expose your contract to known vulnerabilities.
- Test with Edge Cases. Standards define expected behavior, but always test how they interact in your specific protocol setup.
- Verify Governance & Upgradeability Settings. Even a minor misconfiguration in access control can lead to catastrophic consequences.
6. Pay Attention to Off-Chain Dependencies
Many Web3 exploits don’t originate from smart contract bugs alone but from off-chain dependencies that developers often overlook.
Attackers frequently manipulate external systems—such as oracles, multisigs, and RPC endpoints—to bypass on-chain security measures.
A thorough security assessment must go beyond the smart contract and scrutinize every off-chain component it interacts with.
6.1 Key Off-Chain Risks to Watch For
Oracle Manipulations
- Flash Loan Attacks: If a protocol relies on a single price oracle, attackers can use flash loans to distort asset prices temporarily, leading to exploitative liquidations or unfair arbitrage.
- Unsecured Custom Oracles: Many protocols run off-chain price feeds without proper validation, allowing attackers to submit maliciously skewed data to manipulate on-chain decisions.
Insecure Multisig Configurations
- Single-Point-of-Failure in DAOs: Many DAOs assume that a Gnosis Safe multisig is secure, but weak multisig setups (e.g., 3-of-5 signers where two signers are controlled by the same entity) can effectively centralize control, making governance easier to exploit.
- Compromised Signers: If a single multisig signer gets hacked, the attacker can push malicious transactions and drain funds. Always enforce hardware wallet usage and proper key management.
Compromised RPC Endpoints
- Malicious Nodes Injecting False Data: If a project’s frontend relies on a single centralized RPC provider, an attacker controlling that node can serve manipulated blockchain data, tricking users into signing unintended transactions.
- Front-Running Risks: Unencrypted RPC calls can leak transaction intent, allowing MEV bots to front-run user trades for profit.
API & Backend Exploits
- Many cross-chain bridges, authentication systems, and dapps interact with off-chain APIs to execute critical functions. If these APIs lack proper authentication or rate-limiting, attackers can spoof transactions or extract sensitive data.
6.2 How to Secure Off-Chain Dependencies
- Use Aggregated Oracles. Rely on multiple data sources (e.g., Chainlink, Pyth, RedStone) to prevent single-source manipulation.
- Strengthen Multisig Security. Require distributed signers, hardware wallets, and timelocks for critical transactions.
- Validate RPC Responses. Don’t blindly trust RPC calls. Use multiple endpoints and compare results to detect manipulation.
- Harden Off-Chain APIs. Ensure rate-limiting, authentication, and logging for any API interacting with smart contracts.
A smart contract is only as secure as its weakest link and more often than not, that weak link is off-chain.
7. Gas Optimization Can Lead to Security Trade-offs
Gas efficiency is a priority in smart contract development, but optimizing for lower costs at the expense of security is a dangerous trade-off.
We’ve seen cases where excessive gas-saving techniques introduced vulnerabilities—some of which resulted in catastrophic exploits.
Auditors must critically assess whether gas optimizations compromise safety, readability, or upgradability.
7. 1 Common Gas Optimizations That Introduce Risks
Removing Checks for Gas Efficiency
- Unchecked Low-Level Calls: Developers sometimes use
call()
instead of transfer()
or send()
to save gas—but this introduces reentrancy risks if proper checks aren’t enforced. - Skipping
require()
Checks: Some projects remove state validation checks (e.g., verifying ownership, input bounds, or balances) to reduce gas consumption, leaving contracts vulnerable to invalid states or exploits.
Storage Slot Packing & Misalignment
- Solidity allows packing multiple smaller variables (e.g.,
uint8
, bool
) into a single 32-byte storage slot to reduce gas costs. However, incorrect packing can lead to:- Storage misalignment issues in upgrades, breaking compatibility.
- Unexpected overwrites or information leaks due to improper memory layout.
Loop Unrolling & Over-Optimization
- Developers may unroll loops or optimize structs to reduce storage access, but this can introduce:
- Unexpected integer underflows/overflows in edge cases.
- Inflexibility for future upgrades, making bug fixes harder.
Eliminating Events to Save Gas
- Some contracts remove event emissions to cut costs, but this sacrifices on-chain traceability, making forensic investigations and debugging nearly impossible after an exploit.
7. 2 Balancing Gas Optimization & Security
- Prioritize Readability & Maintainability. Overly complex gas optimizations often make audits harder and introduce unintended bugs.
- Always Keep Critical Safety Checks. Never remove reentrancy guards, input validations, or overflow protections just to save gas.
- Use Safe Libraries. Instead of writing gas-optimized arithmetic from scratch, use SafeMath (for older Solidity versions) or Solidity’s built-in overflow protections.
- Optimize Only After Ensuring Security. First, write secure, clear, and correct code—then optimize gas usage without compromising safety.
8. Reentrancy is More Than Just Function Calls
The 2016 DAO hack made reentrancy one of the most well-known vulnerabilities in smart contracts, but many developers still underestimate its complexity.
It’s not just about function calls—reentrancy can manifest in unexpected ways, including token callbacks, low-level calls, and even governance mechanisms.
As auditors, it’s crucial to scrutinize all external interactions to prevent subtle reentrancy exploits.
8. 1 Hidden Reentrancy Risks Beyond Simple Function Calls
Token Callbacks & ERC-777 Risks
- Unlike ERC-20, ERC-777 tokens have a
tokensReceived
hook, allowing attackers to trigger contract logic mid-transaction. If a contract doesn’t properly account for this, an attacker could reenter functions that assume state changes have finalized. - Example: A vulnerable contract updating balances after transferring ERC-777 tokens can be exploited via reentrancy before the state update is complete.
Low-Level Calls (call()
& delegatecall()
)
- Solidity’s
call()
function allows direct Ether transfers to an external contract, but this forwards all available gas, enabling complex reentrant attacks. - Similarly,
delegatecall()
executes code in the caller’s context, meaning malicious contracts can hijack storage variables, creating reentrancy-like effects beyond simple recursive calls.
Cross-Contract Reentrancy
- Some attacks don’t rely on the same function being reentered but instead exploit interconnected contracts. If a protocol interacts with an external lending pool, a DEX, or a staking contract, an attacker could manipulate these interactions to influence token prices, balances, or governance votesbefore state changes finalize.
- Example: A lending protocol that determines collateral value before completing a borrow transaction can be exploited if the attacker reenters and manipulates the asset’s price.
Governance Reentrancy
- Reentrancy isn’t limited to financial transactions—governance systems can also be vulnerable. If a protocol allows users to vote, delegate, or withdraw voting power before finalizing governance actions, attackers can reenter and manipulate proposals or quorum calculations.
- Example: A protocol allowing voting with staked tokens but updating vote weights after function execution can be exploited to vote multiple times before the final state is set.
8.2 How to Defend Against Complex Reentrancy Risks
- Use the Checks-Effects-Interactions Pattern. Always update contract state before making external calls.
- Reentrancy Guards Aren’t Always Enough. While
nonReentrant
modifiers help, they don’t prevent cross-contract or governance-based reentrancy. - Minimize External Calls. Avoid unnecessary interactions with untrusted contracts, especially in fallback functions or token callbacks.
- Set Gas Limits for Low-Level Calls. Explicitly restrict gas forwarding when using
call()
to prevent deep reentrancy chains.
9. AI Can Assist, But Manual Reviews Are Irreplaceable
AI-powered security tools have significantly improved the efficiency of smart contract audits, catching pattern-based vulnerabilities like reentrancy, uninitialized storage variables, and access control flaws.
However, as much as we integrate these tools into our workflow at QuillAudits, we’ve learned that no tool can replace the intuition and critical thinking of an experienced auditor.
Where AI Excels
- Detecting Known Vulnerabilities – AI tools quickly identify common attack vectors like unchecked external calls, integer overflows, and improper function visibility.
- Enhancing Code Coverage – Automated analysis ensures no function or contract section is overlooked, especially in large codebases with thousands of lines.
- Speeding Up the Initial Scan – AI reduces the time spent on basic security checks, allowing auditors to focus on deeper logic analysis.
Where AI Falls Short
- Understanding Business Logic – AI can’t grasp the economic model behind DeFi protocols, making it blind to logic flaws that could result in manipulated tokenomics or infinite minting exploits.
- Missing Contextual Vulnerabilities – Attack vectors often depend on how a contract interacts with external protocols (e.g., lending platforms, DEXs, governance mechanisms). AI can flag potential risks, but only a human can determine their real-world feasibility.
- Adaptive Threats – AI models rely on predefined patterns, but attackers continuously develop new methods. Emerging attack vectors require human-led threat modeling and dynamic security thinking.
At QuillAudits, we use AI to augment our efficiency but always rely on manual reviews for in-depth audits. A proper security assessment isn’t just about identifying vulnerabilities—it’s about understanding intent, business logic, and potential exploitability.
This is exactly why we introduced Multi-Layered Audit framework :)
10. Security Culture Matters
Even the most secure code won’t protect a protocol if the team behind it lacks security awareness. We’ve seen projects with airtight smart contracts still get compromised due to poor operational security—weak multisig setups, leaked private keys, or reckless admin permissions.
10.1 Key Areas Where Teams Often Overlook Security
Multisig & Admin Controls
- A single point of failure in governance can be catastrophic. We've seen projects where a single compromised private key led to the entire protocol being drained. Teams should use multisig wallets (e.g., Safe) with strict access controls to prevent unauthorized actions.
Private Key & Access Management
- Developers sometimes store private keys in environment variables or hardcoded in scripts, making them easy targets. Proper key storage practices—like using hardware wallets or MPC solutions—are non-negotiable.
Operational Security (OpSec) for Founders & Developers
- Attackers don’t just target code—they social-engineer founders, team members, and even auditors. Phishing attacks, deepfake calls, and fake partnership emails have been used to compromise high-profile projects. Security training should extend beyond code to include human risk factors.
Incident Response & Post-Exploitation Handling
- Many teams don’t have an incident response plan. If a hack happens, panic responses lead to poor fund recovery and miscommunication. Having a predefined action plan, forensic team contacts, and crisis communication strategy is essential.
Final Thoughts
Over the past seven years, we’ve seen Web3 security evolve rapidly, from simple smart contract exploits to complex multi-chain attacks. At QuillAudits, we believe that security isn’t just about finding vulnerabilities—it’s about building a resilient ecosystem where projects, developers, and security researchers work together to prevent disasters.
If you’re building in Web3, prioritize security from day one. And if you’re an auditor, never stop learning. The threat landscape is always changing, and staying ahead requires continuous research, collaboration, and innovation.
Want to secure your project? Let’s talk.
Stay safe, stay vigilant.