57796 sc medium signature hashing collision in signatureverifier lets attacker deploy forged accesstoken credittoken metadata critical unintended alteration of what the nft represents
Submitted on Oct 28th 2025 at 22:51:15 UTC by @Codexstar for Audit Comp | Belong
Report ID: #57796
Report Type: Smart Contract
Report severity: Medium
Target: https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/utils/SignatureVerifier.sol
Impacts: Unintended alteration of what the NFT represents (e.g. token URI, payload, artistic content)
Description
Brief / Intro
The platform authorizes collection deployments via signatures checked in SignatureVerifier. These hashes are built with abi.encodePacked over multiple dynamic strings, which is ambiguous. Different (name, symbol, contractURI) (or (name, symbol, uri)) tuples can collide to the same bytes, so a valid signature issued for one tuple can be replayed to deploy a collection with different, forged metadata. This allows unauthorized alteration of what the NFT represents (branding, symbol, contract URI), meeting the Critical impact category.
Vulnerability Details
The authorization hashing for AccessToken and CreditToken uses
abi.encodePackedacross multiple dynamic strings:
// contracts/v2/utils/SignatureVerifier.sol (around line 53)
function checkAccessTokenInfo(address signer, AccessTokenInfo memory accessTokenInfo) external view {
require(
bytes(accessTokenInfo.metadata.name).length > 0 && bytes(accessTokenInfo.metadata.symbol).length > 0,
EmptyMetadata(accessTokenInfo.metadata.name, accessTokenInfo.metadata.symbol)
);
require(
signer.isValidSignatureNow(
keccak256(
abi.encodePacked(
accessTokenInfo.metadata.name,
accessTokenInfo.metadata.symbol,
accessTokenInfo.contractURI,
accessTokenInfo.feeNumerator,
block.chainid
)
),
accessTokenInfo.signature
),
InvalidSignature()
);
}Factorytrusts those verifications and proceeds with deployment:
Why exploitable:
abi.encodePackedconcatenates dynamic strings without boundaries. Example:"abc"||"x"||""equals"ab"||"cx"||"". So a signature for(name='abc', symbol='x', contractURI='')also verifies for(name='ab', symbol='cx', contractURI=''). The factory then deploys the collection with the forged metadata.
Impact Details
Matches in-scope Critical impact “Unintended alteration of what the NFT represents (e.g. token URI, payload, artistic content)”.
Attacker can deploy unauthorized collections with altered
name,symbol,contractURI/uri.Consequences: brand spoofing, user confusion, fraudulent collections appearing authorized, downstream marketplace/dapp trust issues.
References
contracts/v2/utils/SignatureVerifier.sol:53
contracts/v2/utils/SignatureVerifier.sol:81
contracts/v2/platform/Factory.sol:223
contracts/v2/platform/Factory.sol:268
Proof of Concept
Recommendation
Replace
abi.encodePackedwithabi.encodewherever signature hashes include dynamic types inSignatureVerifier.Bind signatures to all critical parameters intended to be controlled by the platform (payment token, prices, supply caps, transferability, etc.).
Add nonce and expiry fields and bind the verifying contract address to prevent replay or cross-contract reuse.
Was this helpful?