57580 sc medium signature replay enables frontrunning of produce producecredittoken

Submitted on Oct 27th 2025 at 10:40:27 UTC by @DoD4uFN for Audit Comp | Belongarrow-up-right

  • Report ID: #57580

  • Report Type: Smart Contract

  • Report severity: Medium

  • Target: https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/platform/Factory.sol

  • Impacts:

    • Griefing (e.g. no profit motive for an attacker, but damage to the users or the protocol)

Description

Brief/Intro

Both the produce() and produceCreditToken() functions in Factory.sol allow users to create new token collections (AccessToken and CreditToken, respectively) after obtaining a valid signature from the platform’s signer. However, the signature verification does not bind the signature to the caller, allowing anyone to reuse a valid signature meant for another user.

As a result, a malicious actor can front-run legitimate creation transactions and deploy the same collection before the rightful creator, permanently blocking them from using the same name and symbol, which are unique identifiers across the platform.

Vulnerability Details

Both produce() and produceCreditToken() rely on EIP-712/ECDSA signature validation to ensure the platform authorizes a collection’s metadata. However, neither the checkAccessTokenInfo() nor checkCreditTokenInfo() functions include the creator’s address in the signed payload. This omission means that a valid signature is reusable by anyone, making it possible for an attacker to frontrun a legitimate user’s collection creation and deploy it under their own address.

For example, in produce():

factoryParameters.signerAddress.checkAccessTokenInfo(accessTokenInfo);
...
bytes32 hashedSalt = _metadataHash(accessTokenInfo.metadata.name, accessTokenInfo.metadata.symbol);
require(getNftInstanceInfo[hashedSalt].nftAddress == address(0), TokenAlreadyExists());

and similarly in produceCreditToken():

In both functions, the deterministic salt is defined as:

Since the salt is derived solely from name and symbol, and uniqueness is enforced via TokenAlreadyExists(), the first entity to call the function with a given (name, symbol) pair “locks” that pair forever.

Impact Details

This vulnerability enables signature replay and collection identity theft across both AccessToken (ERC721) and CreditToken (ERC1155) deployments.

While direct fund loss is not immediate, the exploit effectively breaks creator authorization guarantees the signature mechanism is intended to enforce.

References

  • Factory.sol:produce https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/platform/Factory.sol#L236-L240

  • Factory.sol:produceCreditToken https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/platform/Factory.sol#L306-L310

  • SignatureVerifier.sol https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/utils/SignatureVerifier.sol#L49-L99

  • Factory.sol:_metadataHash https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/platform/Factory.sol#L507

Proof of Concept

Steps

1

Step 1

Alice obtains a valid signature from the factory’s signer for creating a new collection:

  • name = "CoolCats"

  • symbol = "CCAT"

2

Step 2

Alice prepares a transaction calling:

3

Step 3

An attacker monitors the mempool, copies Alice’s transaction data, and resubmits it first with a higher gas price.

4

Step 4

Since msg.sender is not part of the signed payload, the contract accepts the attacker’s transaction as valid.

5

Step 5

The attacker’s transaction deploys the collection first, occupying the salt (CoolCats, CCAT).

6

Step 6

When Alice’s transaction executes, it reverts with TokenAlreadyExists().

7

Step 7

The attacker has effectively stolen the collection name/symbol pair and blocked Alice’s deployment permanently.

Proof of Concept (code)

Should be added in factory.tests.ts @ Deploy AccessToken:

Was this helpful?