Research journal · Security research
Uncovering Front Running Vulnerability with Manually Guided Fuzzing
Learn how Wake's Manually Guided Fuzzing detects front-running vulnerabilities using differential fuzzing. Includes real examples and best practices.
Introduction
Front-running vulnerabilities in smart contracts can pose serious security threats. In this article, we’ll show how Wake’s Manually Guided Fuzzing (MGF) uncovers using differential fuzzing techniques.
What is Manually Guided Fuzzing?
Manually Guided Fuzzing (MGF) is a type of differential fuzzing that:
- Analyses contract logic from multiple perspectives
- Uses Python to test Solidity contracts, encouraging new ways of thinking
- Simplifies testing by using legacy logic patterns
- Makes test cases more understandable and consistent
Example 1: Salt Collision in Account Deployment
Let’s look at a vulnerability that can occur when deploying contracts with CREATE2. If salt calculations are manipulated, address collisions can be made.
Here’s a scenario with multiple deployment paths:
The vulnerability arises when one deployment path can generate the same salt as another, allowing an attacker to front-run the deployment.
Attack Scenario
- An attacker observes a pending transaction using a deployment path with a callback
- The attacker calculates the equivalent
creation_noncefor the direct deployment path - The attacker front-runs with the direct path, deploying to the same address
- The victim’s transaction fails (address already deployed)
- The expected callback never executes
Key Insights for Testing
- Always consider front-running scenarios when testing deployment functions
- Understand how and why salt is used in contract deployment
- Remember that
creation_nonceis user-controlled - Deployment addresses depend only on salt (not the caller address) when using the same factory
To uncover these vulnerabilities, try manipulating variables to find similarities between different deployment paths.
For example, you can set Path1’s creation_nonce to match Path2’s salt calculation.
Example 2: Front-Running ERC-721 Pass Minting
Now, let’s examine an ERC-721 pass contract used for user management.
Tokens are non-transferable, and anyone can call the mint function for any address. Therefore, minting fails if the address already holds a pass by design.
This setup creates a front-running opportunity. An attacker can mint a pass for a victim’s address with their own affiliator, which results in blocking the victim and permanently linking them to the attacker’s affiliate fees.
Attack Impact
- The attacker sees a pending mint transaction for a new member
- The attacker front-runs with their own affiliator address
- The victim’s transaction fails (already minted)
- The victim is permanently linked to the attacker’s affiliator (since the token is non-transferable)
- The attacker receives affiliate fees from the victim’s activities
Testing Insights from Wake
- Wake’s external perspective helps reveal subtle invariants in contract logic
- Testing “weird” invariants can often uncover hidden vulnerabilities
Best Practices for Creating Flow Functions
To maximise your testing, follow these principles:
- Model contract state with general Python data structures, even if the contract uses complex ones
- Validate state variables with print statements and assertions
- Test contract invariants to understand the underlying logic
And use this seven-step methodology:
- Keep each flow function focused on a single transaction
- Use random values for arguments
- Model state with general data structures
- Anticipate operation branches, including reverts
- Don’t rely solely on error outputs or event arguments for branching
- Assert even seemingly unnecessary invariants
- Carefully compare all possible execution paths
Conclusion
Manually Guided Fuzzing with Wake is a powerful method for discovering front-running vulnerabilities. By thinking like an attacker and systematically testing edge cases, MGF helps you find security issues that traditional testing might miss.
Start Manually Guided fuzzing with Wake today.
Vocabulary
Terms used in this article.
-
Differential fuzzing
Differential fuzzing sends generated inputs or action sequences through two implementations and flags behavior that diverges unexpectedly.
-
Front-running
Front-running is transaction ordering that places an actor's transaction before a known pending action to profit from or change its outcome.
-
Fuzz testing
Automated testing that explores many generated inputs or action sequences to find violations of expected properties.
-
Invariant
A property that must remain true before and after every relevant state transition in a system.
-
Manually guided fuzzing
Manually guided fuzzing is stateful fuzz testing in which a researcher writes domain-specific actions, preconditions, state models, and invariants.
-
Smart contract
A smart contract is a program deployed to a blockchain whose state-changing functions execute under the network's deterministic consensus rules.
-
Solidity
Solidity is a statically typed, object-oriented language for writing smart contracts that compile to Ethereum Virtual Machine bytecode.
-
Wake
A Python-based development and testing framework for Solidity with fuzzing, debugging, static analysis, and editor tooling.
Topics