57939 sc medium signature collision via abi encodepacked

  • Submitted on: Oct 29th 2025 at 14:32:39 UTC by @vah_13

  • Report ID: #57939

  • 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)

Brief Description

The SignatureVerifier library uses abi.encodePacked() to hash multiple dynamic strings (name, symbol, URI) for signature verification. This enables boundary-shift collision attacks where an attacker can craft different metadata combinations that produce identical hashes, allowing them to reuse a valid signature for unauthorized collection metadata.

Vulnerability Details

Location

  • File: contracts/v2/utils/SignatureVerifier.sol

  • Lines: 62 (checkAccessTokenInfo), 93 (checkCreditTokenInfo)

Vulnerable Code

Root Cause

When abi.encodePacked() concatenates multiple dynamic types (strings, bytes), it doesn't include length delimiters. This allows boundary-shift collisions:

Example:

  • Legitimate: name="MyToken", symbol="MT" → packed: "MyTokenMT"

  • Malicious: name="MyTokenM", symbol="T" → packed: "MyTokenMT" ← IDENTICAL!

Both produce the same bytes sequence and thus the same keccak256 hash.

Attack Scenario

1

Step 1: Platform backend signs legitimate collection metadata

Name: "Official" Symbol: "NFT" URI: "ipfs://legitimate-metadata" Signature: 0xabcd...

2

Step 2: Attacker crafts colliding metadata

Name: "OfficialN" ← Boundary shifted! Symbol: "FT" ← Boundary shifted! URI: "ipfs://legitimate-metadata"

3

Step 3: Attacker calls produceAccessToken() or produceCreditToken() with:

  • Malicious metadata (OfficialN/FT)

  • Valid signature for legitimate metadata (Official/NFT)

4

Step 4: SignatureVerifier validates the signature because

abi.encodePacked("Official", "NFT", "ipfs://...") == abi.encodePacked("OfficialN", "FT", "ipfs://...") → "OfficialNFTipfs://..." (same bytes!)

5

Step 5: Result

Collection is created with unauthorized metadata that was never explicitly signed by the platform.

Immediate Fix

Replace abi.encodePacked with abi.encode in all signature verification functions:

Proof of Concept

chevron-rightShow PoC (bash script, Solidity tests, and sample output)hashtag

PoC Run Script (bash)


PoC Solidity Tests


Sample Output (abbreviated)

The PoC run confirms collisions with abi.encodePacked and shows that using abi.encode prevents them. Example excerpts:

  • Multiple collision examples: collisions found for pairs like ("Official","NFT") vs ("OfficialN","FT").

  • Real contract vulnerability: checkAccessTokenInfo and checkCreditTokenInfo hash results collide as demonstrated.

  • Fix verified: abi.encode produces different hashes for colliding inputs.

Full logs and test output are contained in the original PoC run (included above).

Recommendations

  • Replace all uses of abi.encodePacked for signature/hashing of multiple dynamic types with abi.encode to preserve unambiguous encoding and prevent boundary-shift collisions.

  • Review other places in the codebase where multiple dynamic types are packed and used for signature verification or critical identifiers, and apply the same fix where applicable.

References

  • Solidity docs on ABI encoding: https://docs.soliditylang.org

  • Example fix applied in immediate fix code snippet above

Was this helpful?