57236 sc medium accesstoken collection front running attack permanent ownership hijack
Submitted on Oct 24th 2025 at 16:01:27 UTC by @failsafe_intern for Audit Comp | Belong
Report ID: #57236
Report Type: Smart Contract
Report severity: Medium
Target: https://github.com/immunefi-team/audit-comp-belong/blob/main/contracts/v2/utils/SignatureVerifier.sol
Impacts:
Theft of unclaimed royalties
Unintended alteration of what the NFT represents (e.g. token URI, payload, artistic content)
Description
Vulnerability Overview
Factory.produce() validates AccessTokenInfo signatures but the signed message omits the intended creator/owner and includes no nonce or expiration. Any party with a valid signature can front-run the legitimate creator and deploy the collection under their own ownership, permanently blocking the rightful deployment due to deterministic salt collision.
Root Cause
SignatureVerifier.sol:51-72 - checkAccessTokenInfo signature omits creator:
function checkAccessTokenInfo(address signer, AccessTokenInfo memory accessTokenInfo) external view {
require(
signer.isValidSignatureNow(
keccak256(
abi.encodePacked(
accessTokenInfo.metadata.name,
accessTokenInfo.metadata.symbol,
accessTokenInfo.contractURI,
accessTokenInfo.feeNumerator,
block.chainid
)
),
accessTokenInfo.signature
),
InvalidSignature()
);
}Missing from hash: intended creator address, nonce, expiration timestamp.
Factory.sol:175-239 - produce sets creator = msg.sender after signature validation:
Attack Flow
Impact
Impact Category: Unintended alteration of what the NFT represents (e.g. token URI, payload, artistic content)
Operational Damage:
Complete ownership takeover: Attacker controls collection royalties, minting, metadata, and all creator functions
Brand capture: Legitimate creator permanently blocked from using their own collection name/symbol
Royalty theft: Attacker receives all secondary sale royalties intended for legitimate creator
Reputation damage: Fake collection under attacker control tarnishes brand
No recovery: Deterministic deployment prevents legitimate redeployment without contract upgrade
Business Impact:
Creators lose anticipated royalty revenue (potentially significant for popular collections)
Platform reputation damaged when creators discover collections hijacked
Backend signature credentials must be immediately rotated if compromised
Legal/customer support costs to resolve ownership disputes
Link to Proof of Concept
https://gist.github.com/Joshua-Medvinsky/35c232c0b9da435fd072f742319671c0
Proof of Concept
GitHub Gist POC: https://gist.github.com/Joshua-Medvinsky/35c232c0b9da435fd072f742319671c0
Test Results: ✅ 7/7 tests passed (front-running, permanent blocking, royalty theft demonstrated)
Prerequisites
Attack Execution
Expected vs Actual Behavior
Expected: Signature should authorize collection creation only for a specific creator address.
Actual: Signature authorizes collection creation for ANY caller, enabling first-come-first-served ownership race.
Recommended Fix
Immediate Fix (Contract Upgrade Required)
Modify checkAccessTokenInfo to include the intended creator in the signed payload:
Update Factory.produce to bind the signature to the caller:
Add nonce protection:
Add state variable in Factory:
Add nonce to
AccessTokenInfostruct:
Include nonce in signature hash:
Validate and increment in
produce():
Add expiration timestamp:
Add to
AccessTokenInfostruct:
Validate in
produce():
Defense-in-Depth Recommendations
Commit-Reveal Scheme: Creator commits to deployment before revealing signature
Allowlist: Maintain on-chain registry of creator addresses authorized to deploy
Two-Step Deployment: Creator registers intent on-chain before final deployment
Backend Rate Limiting: Issue signatures only after verifying requester identity
Signature Revocation: Backend maintains revocable signature registry
References
Vulnerable Function:
checkAccessTokenInfo(SignatureVerifier.sol:51-72)Exploitable Function:
produce(Factory.sol:175-239)Ownership Assignment:
AccessToken.initialize(AccessToken.sol:86-101)Deterministic Salt:
_metadataHash(Factory.sol:193)
Was this helpful?