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

  1. An attacker observes a pending transaction using a deployment path with a callback
  2. The attacker calculates the equivalent creation_nonce for the direct deployment path
  3. The attacker front-runs with the direct path, deploying to the same address
  4. The victim’s transaction fails (address already deployed)
  5. 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_nonce is 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:

  1. Model contract state with general Python data structures, even if the contract uses complex ones
  2. Validate state variables with print statements and assertions
  3. Test contract invariants to understand the underlying logic

And use this seven-step methodology:

  1. Keep each flow function focused on a single transaction
  2. Use random values for arguments
  3. Model state with general data structures
  4. Anticipate operation branches, including reverts
  5. Don’t rely solely on error outputs or event arguments for branching
  6. Assert even seemingly unnecessary invariants
  7. 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.