skills/protocol-patterns/bridges-cross-chain/SKILL.md
Cross-chain bridge security guidance for message verification, replay prevention, and validator risk.
npx skillsauth add apegurus/solidity-argus bridges-cross-chainInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Bridges transfer assets/messages between blockchains. They are the highest-value targets in DeFi — $2B+ stolen from bridges. Core security concerns: message verification, validator security, and replay attacks.
┌─────────────────┐ ┌─────────────────┐
│ Chain A │ │ Chain B │
│ │ │ │
│ ┌───────────┐ │ Message │ ┌───────────┐ │
│ │ Bridge │ │ ──────────────────► │ │ Bridge │ │
│ │ Contract │ │ │ │ Contract │ │
│ └───────────┘ │ │ └───────────┘ │
│ │ │ │ │ │
│ Lock/Burn │ ┌──────────────┐ │ Mint/Unlock │
│ Tokens │ │ Validators │ │ Tokens │
│ │ │ / Relayers │ │ │
└─────────────────┘ └──────────────┘ └─────────────────┘
│
Sign attestations
Attack Vectors:
Checklist:
// VULNERABLE: Incomplete verification
function processMessage(
bytes32 messageHash,
bytes[] calldata signatures
) external {
uint256 validSigs;
for (uint i; i < signatures.length; i++) {
address signer = recoverSigner(messageHash, signatures[i]);
if (isValidator[signer]) validSigs++;
}
require(validSigs >= threshold, "Not enough sigs");
// Missing: Check for duplicate signers!
}
// SECURE: Track used signatures
function processMessage(
bytes32 messageHash,
bytes[] calldata signatures
) external {
uint256 validSigs;
address lastSigner;
for (uint i; i < signatures.length; i++) {
address signer = recoverSigner(messageHash, signatures[i]);
require(signer > lastSigner, "Invalid sig order"); // Prevents duplicates
if (isValidator[signer]) validSigs++;
lastSigner = signer;
}
require(validSigs >= threshold, "Not enough sigs");
}
Attack Vectors:
Checklist:
// VULNERABLE: No replay protection
function executeMessage(bytes calldata message, bytes calldata proof) external {
require(verifyProof(message, proof), "Invalid proof");
_execute(message); // Can be called again with same message!
}
// SECURE: Mark as processed
mapping(bytes32 => bool) public processedMessages;
function executeMessage(bytes calldata message, bytes calldata proof) external {
bytes32 messageHash = keccak256(message);
require(!processedMessages[messageHash], "Already processed");
require(verifyProof(message, proof), "Invalid proof");
processedMessages[messageHash] = true;
_execute(message);
}
Attack Vectors:
Checklist:
Attack Vectors:
Checklist:
// Ideal invariant
assert(wrappedTokenSupply <= originalTokenLockedAmount);
Attack Vectors:
Checklist:
What happened:
Root cause: Insufficient validator distribution + social engineering
What happened:
Root cause: Invalid signature verification on Solana side
What happened:
Root cause: Zero initialization treated as valid state
// The Nomad bug pattern
mapping(bytes32 => uint256) public messages;
function process(bytes memory _message) public {
bytes32 _messageHash = keccak256(_message);
// messages[_messageHash] == 0 was treated as confirmed!
require(acceptableRoot(messages[_messageHash]), "not accepted");
}
What happened:
Root cause: Insufficient validation of cross-chain call targets
struct Message {
uint256 srcChainId;
uint256 dstChainId;
address srcContract;
address dstContract;
uint256 nonce;
bytes payload;
}
function hashMessage(Message memory m) internal pure returns (bytes32) {
return keccak256(abi.encode(
m.srcChainId,
m.dstChainId,
m.srcContract,
m.dstContract,
m.nonce,
keccak256(m.payload)
));
}
function verifySignatures(
bytes32 hash,
bytes[] calldata sigs
) internal view returns (bool) {
address lastSigner = address(0);
uint256 valid;
for (uint i; i < sigs.length; i++) {
address signer = ECDSA.recover(hash, sigs[i]);
require(signer > lastSigner, "Signatures not ordered");
if (guardians[signer]) valid++;
lastSigner = signer;
}
return valid >= threshold;
}
testing
Specialist profile for mechanically applying the attack-vector deck and classifying vectors as skip, drop, or investigate.
tools
Specialist profile for libraries, helpers, base contracts, adapters, encoders, wrappers, and integration glue.
testing
Specialist profile for rounding, scale, decimal, downcast, and arithmetic accounting edge cases.
testing
Specialist profile for extracting conservation laws and state couplings, then searching for violating paths.