Writing Audit-Ready Test Suites That Map Directly to Threat Scenarios
Smart contract audits cost between $50,000 and $300,000, yet 90% of exploited contracts were previously audited. The gap between passing an audit and remaining secure in production stems from a fundamental mismatch: auditors examine code at a single point in time, while attackers probe deployed contracts continuously for vulnerabilities.
Audit-ready test suites bridge this gap by mapping test cases directly to known threat scenarios. Rather than generic unit tests that verify basic functionality, threat-mapped test suites demonstrate to auditors that developers understand attack vectors and have systematically defended against them.
The Audit Preparation Problem
Traditional test suites focus on happy path scenarios and basic edge cases. Developers write tests to verify that functions execute correctly under expected conditions. This approach satisfies code coverage metrics but leaves auditors questioning whether the development team considered realistic attack scenarios.
When auditors review a smart contract, they spend the first portion of their engagement understanding the protocol's security assumptions and potential attack surfaces. Projects that arrive at audit without threat-specific test cases force auditors to start from scratch, increasing both audit duration and findings severity.
A test suite that maps directly to threat scenarios accelerates the audit process by demonstrating that the development team has already considered common attack vectors. Auditors can validate the team's threat model rather than building one from scratch, focusing their expertise on novel vulnerabilities specific to the protocol's unique logic.
Understanding Threat Scenario Mapping
Threat scenario mapping connects specific test cases to documented attack patterns in Web3 security. Rather than writing a test labeled "test_withdraw_functionality," a threat-mapped test suite includes "test_prevents_reentrancy_during_withdrawal" that explicitly references the reentrancy vulnerability class.
This approach serves three purposes. First, it forces developers to think like attackers during the development process rather than treating security as an afterthought. Second, it creates living documentation that explains security decisions to auditors and future developers. Third, it enables systematic verification that all known threat vectors have corresponding defensive tests.
The most effective threat-mapped test suites organize tests by vulnerability category rather than by contract function. Instead of grouping all tests for a single function together, security-focused test organization groups all reentrancy tests together, all access control tests together, and all oracle manipulation tests together.
Common Threat Categories for DeFi Protocols
DeFi protocols face recurring threat patterns that should map directly to test scenarios. Reentrancy attacks remain prevalent despite widespread awareness because protocols continue introducing subtle variations that bypass standard guards. Test suites should include reentrancy scenarios for every state-changing function that calls external contracts, including both single-function reentrancy and cross-function reentrancy patterns.
Access control vulnerabilities represent another high-frequency category. Test suites should verify that privileged functions reject unauthorized callers, that role transitions follow correct sequences, and that ownership transfers cannot be frontrun or manipulated. Time-dependent access patterns require specific test coverage, particularly for functions with different permissions during different protocol states.
Oracle manipulation tests verify that price feeds cannot be manipulated through flash loans, that stale prices are rejected, and that circuit breakers activate under extreme conditions. Integer overflow and underflow tests remain relevant for contracts that perform complex calculations, particularly those involving token decimals or scaling factors.
Frontrunning and MEV scenarios test whether the protocol remains secure when transactions execute in adversarial orderings. This includes verifying that slippage protections work correctly, that sandwich attacks cannot extract value, and that time-sensitive operations include appropriate deadlines.
Structuring Tests Around Attack Vectors
Effective threat-mapped test suites begin with threat modeling before writing code. The development team documents potential attack vectors based on similar protocols, known vulnerability patterns, and the unique logic of their system. Each documented threat becomes a test category that must achieve complete coverage.
Test naming conventions should explicitly reference the threat being tested. Instead of generic names, use descriptive labels like "test_reentrancy_via_callback_during_deposit" or "test_oracle_manipulation_via_flashloan_sandwich." This naming approach makes it immediately clear to auditors which threats have test coverage and which might need additional attention.
Each test should include comments explaining the threat scenario, why it matters for the specific protocol, and how the implemented defense prevents the attack. Comments should reference specific security incidents when applicable. For example, a reentrancy test might reference the 2016 DAO hack or the 2023 Curve Finance incident, explaining how the protocol's specific implementation prevents similar attacks.
Test organization should follow a consistent hierarchy: vulnerability category, specific attack vector, and then variations on that attack vector. A reentrancy test category might include subcategories for single-function reentrancy, cross-function reentrancy, and read-only reentrancy. Each subcategory then includes tests for different entry points and callback scenarios.
Implementing Attack Simulations in Tests
Threat-mapped tests go beyond simple assertions about correct behavior. They actively simulate attack scenarios using the same techniques real attackers employ. This requires creating malicious contracts that attempt to exploit the protocol, then verifying that defensive mechanisms prevent the attack.
For reentrancy testing, create attack contracts that implement the same callback interfaces your protocol calls. These attack contracts should attempt to re-enter protocol functions at every possible state-changing operation. Tests should verify not just that reentrancy fails, but that it fails safely without leaving the protocol in an inconsistent state.
Oracle manipulation tests require setting up scenarios with manipulated price feeds. Rather than mocking oracle responses directly, simulate the sequence of transactions an attacker would execute. Deploy mock DEXs, execute flash loans, manipulate pools, and verify that the protocol correctly rejects manipulated prices or activates circuit breakers.
Access control tests should attempt privilege escalation through various vectors. Test frontrunning of ownership transfers, verify that temporary privilege grants cannot be extended, and confirm that emergency functions remain callable by appropriate parties even during attacks. Each test should demonstrate not just that unauthorized access fails, but that the failure mode prevents state corruption.
Frontrunning scenarios require testing different transaction orderings. Use tools like Hardhat's mainnet forking and transaction sequencing capabilities to simulate MEV bot behavior. Verify that slippage protections work correctly, that time locks prevent sandwich attacks, and that critical operations remain atomic even under adversarial conditions.
Test Coverage Metrics That Matter for Security
Standard code coverage metrics measure whether tests execute each line of code but fail to capture whether tests validate security properties. Audit-ready test suites require security-specific coverage metrics that track threat scenario coverage rather than line coverage alone.
Branch coverage gains importance for security testing because attackers specifically target conditional logic. Every require statement, every if condition, and every modifier guard represents a potential bypass target. Tests should verify both the success case where conditions pass and the failure case where they correctly reject invalid inputs.
State coverage measures whether tests exercise all possible contract states, including edge states that occur during attacks. For protocols with lifecycle stages, tests must verify security properties in every stage and during transitions between stages. For protocols with emergency modes, tests must verify that emergency functions work correctly and cannot be abused.
Mutation testing provides the most rigorous security coverage metric by introducing deliberate bugs and verifying that tests catch them. A mutation testing tool modifies operators, changes constants, removes require statements, and inverts conditions. The test suite should fail when these mutations introduce vulnerabilities. Olympix's mutation testing capabilities help teams identify gaps in threat coverage by showing which security-critical code changes fail to trigger test failures.
Integration with Formal Verification
Formal verification tools analyze code mathematically to prove security properties. Rather than replacing tests, formal verification complements threat-mapped test suites by providing proofs for properties that would require exponentially many test cases to cover exhaustively.
Integrating formal verification with test suites requires specifying invariants that represent security properties. For token vaults, an invariant might state that total shares always equal the sum of individual balances. For lending protocols, invariants specify that total borrowed cannot exceed total supplied plus protocol reserves.
Tests serve as examples that validate formal specifications are correct. When formal verification proves an invariant holds, tests verify that the invariant captures the intended security property by demonstrating attack scenarios that would violate alternative specifications. This feedback loop ensures that formal proofs address real threats rather than proving irrelevant properties.
Olympix's symbolic execution capabilities identify code paths that could violate invariants. Rather than waiting for auditors to discover edge cases, symbolic execution explores all possible execution paths and generates test cases for scenarios that might violate security properties. Teams can incorporate these automatically generated tests into their test suites, ensuring comprehensive coverage of complex state spaces.
Documentation That Auditors Need
Audit-ready test suites include documentation that explains the threat model, testing approach, and rationale for specific test scenarios. This documentation accelerates the audit process by answering questions before auditors need to ask them.
The threat model document lists potential attack vectors, explains why each matters for the specific protocol, and references the test category that covers each threat. When documenting known attack patterns, reference specific security incidents and explain how the protocol's design prevents similar attacks. This demonstrates to auditors that the development team learned from historical exploits rather than repeating past mistakes.
Each test category should include a README explaining the threat being tested, known incidents involving that threat type, and how the protocol's defenses prevent the attack. Link to relevant security resources like audits of similar protocols, academic papers on the vulnerability class, and blog posts explaining attack techniques.
Test comments should explain not just what each test does but why the specific scenario matters. Rather than commenting "checks reentrancy guard works," explain "verifies that callback during withdrawal cannot drain protocol because reentrancy guard prevents re-entering withdraw function before state updates complete, addressing same pattern that enabled $121M Balancer exploit."
Continuous Testing Throughout Development
Threat-mapped test suites provide maximum value when integrated into continuous development workflows. Rather than writing tests only before audit, teams should expand test coverage iteratively as they develop new features and discover new threat scenarios.
Every pull request should include tests for security properties affected by code changes. Code review processes should verify not just that new code works correctly but that tests demonstrate security against relevant threats. This approach catches vulnerabilities during development rather than during expensive audit cycles.
Automated testing pipelines should run the complete threat-mapped test suite on every commit. When tests fail, the development team immediately knows which threat scenario the code change violated. This rapid feedback prevents security regressions and ensures the protocol maintains its security posture as features evolve.
Static analysis integration identifies potential vulnerabilities that might lack test coverage. Tools that detect reentrancy risks, unchecked external calls, or dangerous delegatecalls should trigger automated test generation for the identified patterns. Olympix's static analysis capabilities flag security issues during development, allowing teams to write corresponding tests before vulnerabilities reach production.
Fuzzing and Property-Based Testing
Fuzzing generates random inputs to discover unexpected behavior that manual test cases might miss. Property-based testing extends fuzzing by verifying that security properties hold across randomly generated scenarios rather than just checking that code doesn't crash.
Integrating fuzzing into threat-mapped test suites requires defining properties that represent security invariants. For token contracts, properties might specify that transfers cannot create or destroy tokens. For AMMs, properties verify that swaps maintain pool invariants and cannot be manipulated to drain liquidity.
Fuzzing discovers edge cases that manual testing overlooks. While threat-mapped tests verify known attack patterns, fuzzers explore input spaces too large for manual enumeration. The combination provides defense against both known attack vectors and novel exploitation techniques.
Olympix's fuzzing capabilities operate continuously rather than as a one-time pre-audit check. As protocols evolve and new features deploy, continuous fuzzing discovers regressions and unexpected interactions between components. Teams integrate fuzzing results into their test suites, converting discovered edge cases into permanent regression tests.
Preparing for the Audit Handoff
When submitting a protocol for audit, the test suite becomes a critical communication tool. Auditors assess protocol security based partly on test quality because comprehensive tests demonstrate that the development team understands security implications of their code.
The audit handoff package should include a test coverage report that maps threat scenarios to test categories. This report should explicitly list any known threats that lack complete test coverage, explaining whether the team accepts the risk, plans future mitigation, or specifically wants auditor focus on those areas.
Include instructions for running the complete test suite in different configurations. Auditors should be able to execute tests against mainnet forks to verify behavior matches expectations under realistic conditions. Provide configuration for running tests with different gas settings, block times, and network conditions to demonstrate the protocol functions correctly across deployment environments.
Document any test assumptions or limitations. If tests make simplifying assumptions about external protocols, oracle behavior, or governance actions, explicitly state these assumptions. Auditors need to know which scenarios tests cover and which require additional analysis.
Converting Audit Findings Into Tests
Post-audit, teams should convert every finding into a test case that demonstrates the vulnerability and verifies the fix. This creates a permanent regression test suite that prevents reintroducing fixed vulnerabilities in future updates.
For each audit finding, create a test that reproduces the vulnerable behavior before the fix. This test should fail in the vulnerable version and pass after applying the fix. Include detailed comments explaining the vulnerability, how it was discovered, and why the fix prevents exploitation.
Audit findings often reveal blind spots in the original threat model. Teams should expand their threat-mapped test categories to include newly discovered attack patterns. This iterative improvement ensures that test suites evolve with the protocol's security understanding rather than remaining static after initial development.
Moving Security Left in the Development Process
Traditional Web3 security treats auditing as a final gate before deployment. This approach discovers vulnerabilities late when fixes are expensive and timeline pressure tempts teams to accept risks. Threat-mapped test suites shift security left by integrating security validation throughout development.
When developers write security tests alongside feature code, they catch vulnerabilities immediately rather than weeks later during audit. This approach reduces audit findings by 30-80% because the development team already validated the code against known threats before auditors examine it.
Proactive security tools like Olympix's static analysis, mutation testing, and fuzzing capabilities enable continuous security validation. Rather than waiting for periodic audits, teams detect and fix vulnerabilities during normal development cycles. This approach complements auditing rather than replacing it, ensuring that auditors focus on novel protocol-specific risks rather than discovering common vulnerability patterns.
Building Security Into Development Culture
Audit-ready test suites reflect a broader cultural shift toward security-first development. Rather than treating security as an audit firm's responsibility, teams that maintain comprehensive threat-mapped tests take ownership of their protocol's security posture.
This cultural shift requires training developers to think like attackers. Security workshops, incident post-mortems, and regular threat modeling sessions help teams internalize common attack patterns. When developers understand how protocols get exploited, they naturally write better defensive code and more comprehensive tests.
Security champions within development teams advocate for test quality and ensure that security remains a priority even under deadline pressure. These champions review pull requests for security implications, maintain the threat model documentation, and ensure new features include corresponding threat-mapped tests.
Conclusion
Audit-ready test suites that map directly to threat scenarios represent a fundamental shift in smart contract security. Rather than treating audits as security validation, teams use comprehensive testing to validate security continuously throughout development. This approach catches vulnerabilities earlier, reduces audit findings, and creates documentation that accelerates the audit process.
The most effective test suites go beyond code coverage metrics to verify security properties explicitly. By organizing tests around attack vectors rather than contract functions, teams demonstrate security understanding to auditors and create living documentation for future developers.
Tools like Olympix's static analysis, mutation testing, and fuzzing capabilities enable teams to maintain audit-ready test suites without dedicated security expertise. By integrating proactive security validation into development workflows, teams shift security left and catch vulnerabilities before they reach production.
The goal extends beyond passing a single audit. Comprehensive threat-mapped test suites provide continuous security validation as protocols evolve, protecting user funds throughout the protocol's lifecycle rather than just at initial deployment.
Shift Security Left with Olympix
Stop waiting for audits to discover vulnerabilities your tests should have caught. Olympix's proactive security platform helps development teams write audit-ready code before it reaches production.
Our static analysis detects vulnerabilities during development. Mutation testing validates that your test suite actually catches security issues. Automated fuzzing discovers edge cases manual testing misses. All integrated into your existing development workflow.
Reduce audit findings by 30-80% and accelerate your path to production with security tools built for Web3 developers.
Trusted by Circle, Uniswap Foundation, and Cork Protocol to secure billions in DeFi value.
What’s a Rich Text element?
The rich text element allows you to create and format headings, paragraphs, blockquotes, images, and video all in one place instead of having to add and format them individually. Just double-click and easily create content.
A rich text element can be used with static or dynamic content. For static content, just drop it into any page and begin editing. For dynamic content, add a rich text field to any collection and then connect a rich text element to that field in the settings panel. Voila!
Headings, paragraphs, blockquotes, figures, images, and figure captions can all be styled after a class is added to the rich text element using the "When inside of" nested selector system.
Follow-up: Conduct a follow-up review to ensure that the remediation steps were effective and that the smart contract is now secure.
Follow-up: Conduct a follow-up review to ensure that the remediation steps were effective and that the smart contract is now secure.
In Brief
Remitano suffered a $2.7M loss due to a private key compromise.
GAMBL’s recommendation system was exploited.
DAppSocial lost $530K due to a logic vulnerability.
Rocketswap’s private keys were inadvertently deployed on the server.
Hacks
Hacks Analysis
Huobi | Amount Lost: $8M
On September 24th, the Huobi Global exploit on the Ethereum Mainnet resulted in a $8 million loss due to the compromise of private keys. The attacker executed the attack in a single transaction by sending 4,999 ETH to a malicious contract. The attacker then created a second malicious contract and transferred 1,001 ETH to this new contract. Huobi has since confirmed that they have identified the attacker and has extended an offer of a 5% white hat bounty reward if the funds are returned to the exchange.