DatingDapp

First Flight #33
Beginner FriendlyFoundrySolidityNFT
100 EXP
View results
Submission Details
Severity: low
Invalid

Predictable Sequential ID Generation leads to front running and Precise prediction of future token IDs

Vulnerability Details

affected line of code

In the mintProfile function

uint256 tokenId = ++_nextTokenId;

This current implementation uses a sequential ID generation system that increments a counter for each new profile mint. This predictable pattern allows malicious actors to:

  • Front-run transactions to obtain specific IDs

    Uses a simple incrementing counter

  • Provides no entropy or randomness

  • Makes future IDs completely predictable

Below are a set of POC's that demonstrates the identified vulnerability

copy and paste this test into SoulboundProfileNFT.t.sol

and run it


This Number 1 test demonstrates the fundamental vulnerability by showing that:

The first mint always generates ID 1

The second mint always generates ID 2

The sequence is completely predictable and deterministic

function testPredictableIDGeneration() public {
// Arrange
string memory name = "Test Profile";
uint8 age = 25;
string memory profileImage = "test-image-uri";
// Act
vm.prank(user);
soulboundNFT.mintProfile(name, age, profileImage);
// Assert
uint256 firstId = soulboundNFT.profileToToken(user);
assertEq(firstId, 1, "First ID should be 1");
vm.prank(user2);
soulboundNFT.mintProfile(name, age, profileImage);
// Assert
uint256 secondId = soulboundNFT.profileToToken(user2);
assertEq(secondId, 2, "Second ID should be 2");
}

This Number 2 test shows how an attacker can:

Monitor the blockchain for pending transactions

```See a user's mint transaction with ID 1`

Prepare their own mint transaction to get ID 2

Potentially manipulate market dynamics or token distribution

function testFrontRunningAttack() public {
// Arrange
string memory name = "Test Profile";
uint8 age = 25;
string memory profileImage = "test-image-uri";
// Act
vm.prank(user);
soulboundNFT.mintProfile(name, age, profileImage);
// Act again with attacker
vm.prank(attacker1);
soulboundNFT.mintProfile(name, age, profileImage);
// Assert
uint256 userId = soulboundNFT.profileToToken(user);
uint256 attackerId = soulboundNFT.profileToToken(attacker1);
assertEq(userId, 1, "User should have ID 1");
assertEq(attackerId, 2, "Attacker should have ID 2");
}

This Final test shows how multiple actors can:

Interact with the contract in sequence

Each reliably receive the next sequential ID

The sequence remains predictable even with multiple users````No randomness or unpredictability is introduced

function testIDManipulation() public {
// Arrange
string memory name = "Test Profile";
uint8 age = 25;
string memory profileImage = "test-image-uri";
// Act
vm.prank(user);
soulboundNFT.mintProfile(name, age, profileImage);
// Act again with different user
vm.prank(user2);
soulboundNFT.mintProfile(name, age, profileImage);
// Act with attacker trying to manipulate ID
vm.prank(attacker1);
soulboundNFT.mintProfile(name, age, profileImage);
// Assert
uint256 userId = soulboundNFT.profileToToken(user);
uint256 user2Id = soulboundNFT.profileToToken(user2);
uint256 attackerId = soulboundNFT.profileToToken(attacker1);
assertEq(userId, 1, "User should have ID 1");
assertEq(user2Id, 2, "User2 should have ID 2");
assertEq(attackerId, 3, "Attacker should have ID 3");
}

Impact Assessment:

The vulnerability enables several attack vectors:

  • Front-running Attacks
    Attackers can prepare transactions knowing exact IDs

  • Strategic positioning in transaction queue

  • Potential for ID-based market manipulation

Tools Used

manual review and foundry

Recommendations

  • Uses multiple entropy sources for unpredictability

  • Includes user-specific data to prevent ID collisions

  • Implements blockhash from previous block to prevent miner manipulation

Updates

Appeal created

n0kto Lead Judge 5 months ago
Submission Judgement Published
Invalidated
Reason: Design choice
Assigned finding tags:

Informational or Gas

Please read the CodeHawks documentation to know which submissions are valid. If you disagree, provide a coded PoC and explain the real likelyhood and the detailed impact on the mainnet without any supposition (if, it could, etc) to prove your point.

Support

FAQs

Can't find an answer? Chat with us on Discord, Twitter or Linkedin.