Security Playground Logo
Auditor-Grade Analysis

The Selector Collision Primitive

A deep dive into the mechanical failure of the Poly Network cross-chain bridge. We analyze the raw ABI encoding, the EVM call stack transitions, and the architectural flaws that allowed a 4-byte hash collision to bypass privilege checks.

1. Raw Selector Mechanics

The core vulnerability wasn't just "bad code"—it was a mathematical collision exploited through a dynamic dispatcher. The breakdown below shows the exact Keccak-256 calculations used by the attacker.

Target Function

// The restricted function we want to call
putCurEpochConPubKeyBytes(bytes)
Keccak256:41973cd9...
Selector (first 4 bytes):0x41973cd9

Exploit Collision

// The method string attacker provided
f1121318093(bytes,bytes,uint64)
Keccak256:41973cd9...
Selector (first 4 bytes):0x41973cd9

Why is this 4-byte collision feasible?

Unlike a full 256-bit hash collision (computationally impossible), finding a collision in just the first 32 bits (4 bytes) is relatively trivial.

Search Space: 2^32 ≈ 4.29 billion

Birthday Paradox: ~77,000 hashes = 50% chance

// Can be brute-forced on a laptop in minutes.

The attacker tailored the string "f1121318093" (likely one of millions generated) so that when the Manager contract appended the mandatory suffix (bytes,bytes,uint64), the resulting hash began with the magic bytes 41973cd9.

Verification (Run in Console)

const ethers = require('ethers');

// Target Function
const target = ethers.id('putCurEpochConPubKeyBytes(bytes)').slice(0, 10);
console.log(target); // 0x41973cd9

// Collision String
const exploit = ethers.id('f1121318093(bytes,bytes,uint64)').slice(0, 10);
console.log(exploit); // 0x41973cd9

console.log('Match:', target === exploit); // true

2. EVM Call Trace

The real catastrophe wasn't just the collision—it was the Context Hijacking. The EthCrossChainData contract implicitly trusted calls coming from its owner, the EthCrossChainManager.

1
External Transaction (EOA → Manager)
Attacker calls verifyHeaderAndExecuteTx(...)
msg.sender: Attacker (0x123...)
_method: "f1121318093"
2
Contract Logic (Manager)
Calculates Selector & Executes RAW CALL
bytes4 selector = bytes4(keccak256(...)) // Result: 0x41973cd9
address(eccd).call(abi.encodePacked(selector, args));
Call Data Structure:
[41973cd9]...args...
// The first 4 bytes match the target selector exactly
3
Context Switch (Data Contract)
CRITICAL BYPASS
Receives Call: putCurEpochConPubKeyBytes(...)
Current Context:
msg.sender: EthCrossChainManager (0xABC...)
onlyOwner check PASSES (Manager IS the owner)

3. Educational vs. Real World

ComponentThis PlaygroundReal Poly Network
Selector Collision AccurateUsed exactly as demonstrated.
Access Control AccurateManager contract was indeed the Owner of Data contract.
Architecture SimplifiedReal system had complex Merkle Proof verification wrapping the call.
(The attacker forged this proof first to reach the vulnerable code).
Signature Validation OmittedAttacker had to forge/bypass header validation logic first.

Why was this designed this way?

The developers wanted extensibility. By allowing the Manager contract to construct calls dynamically, they theoretically allowed it to support future cross-chain message types without redeploying the main contract.

"Generic Execution" patterns are the single most dangerous design choice in smart contract security.

Pattern Mapping

This "privileged executor" vulnerability is not unique to bridges. It appears in:

  • Governance Executors: DAOs passing arbitrary calldata.
  • Meta-Transaction Relayers: Forwarders acting on signed messages.
  • Diamond Proxies: Complex selector routing logic.

Prerequisites

Required knowledge to understand this exploit.

EVM Selector Logic

First 4 bytes of calldata identify the function.

ABI Encoding

How arguments are packed in raw bytes.

CALL vs DELEGATECALL

Understanding context switching.

Access Control

Modifiers like onlyOwner.