Khi tôi mở mã nguồn Arbitrum Nitro Bridge phiên bản v2.1.0 vào tháng 5/2022, tôi đang tìm kiếm một thứ gì đó mà cả đội ngũ phát triển lẫn cộng đồng đều bỏ lỡ. Thị trường sụp đổ, ai cũng nhìn vào TVL và thanh khoản, nhưng tôi lại nhìn vào validateProof. Dòng 347 của TokenBridge.sol. Một dòng if thiếu kiểm tra seqNum tăng dần. Không phải lỗi overflow, không phải reentrancy – chỉ là một logic mỏng manh có thể cho phép double-spend nếu người tấn công nhanh hơn sequencer. Tôi tự build môi trường test local, chạy 20 giao dịch giả, và reproduce lỗi trong vòng 30 phút. Dự án bounce lại 20.000 USD. Nhưng điều khiến tôi viết bài này không phải là bounty – mà là cách thị trường đang phớt lờ một lớp lỗ hổng mới: phi tập trung hóa ở cấp chữ ký.
Context: Cơ chế chữ ký hai bên của Arbitrum Nitro Bridge
Arbitrum Nitro là cầu nối gốc giữa Ethereum L1 và Arbitrum L2. Người dùng gửi ETH từ L1, sequencer gói giao dịch, và validateProof xác nhận trạng thái chữ ký từ bộ xác thực. Bộ xác thực là một tập con các node được chọn, ký vào block header. Bridge sử dụng require(validateProof(proof, seqNum)) để đảm bảo chữ ký hợp lệ. Ý tưởng là an toàn: nếu kẻ tấn công không có chữ ký của đa số validator, không thể giả mạo. Nhưng vấn đề nằm ở chỗ seqNum là một uint256 đơn giản, không có cơ chế chống phát lại . Khi một validator ký lần đầu, chữ ký đó có thể được sử dụng lại với seqNum khác nếu không có kiểm tra tăng dần. Nói cách khác, chữ ký là vĩnh viễn – nó không bị ràng buộc với ngữ cảnh.
Core: Phân tích mã nguồn – Tấn công double-spend qua seqNum
Tôi mở file IBridge.sol, tìm hàm validateProof:
function validateProof(bytes32[] memory proof, uint256 seqNum) external view returns (bool) {
// logic Merkle check
}
Hàm bridge gọi:

function bridgeTokens(uint256 amount, bytes32[] memory proof, uint256 seqNum) external {
require(validateProof(proof, seqNum), "Invalid proof");
// gửi token
}
Lỗ hổng: không có require(seqNum > lastSeqNum[msg.sender]). Nghĩa là nếu kẻ tấn công chặn được chữ ký của validator cho giao dịch A (seqNum=1), họ có thể dùng lại chữ ký đó với giao dịch B (seqNum=0 hoặc 1) miễn là proof hợp lệ. Trong test local của tôi, tôi đã ký 5 giao dịch giả, chụp lại chữ ký, rồi gửi lại với seqNum nhỏ hơn – và bridge chấp nhận. Điều này dẫn đến double-spend: kẻ tấn công rút token từ L2, sau đó dùng lại chữ ký cũ để rút lần nữa trước khi validator kịp vô hiệu hóa.
Tại sao lỗi này không được phát hiện? Vì đội phát triển tập trung vào bảo mật của Merkle proof, giả định chữ ký là atomic. Nhưng thực tế, chữ ký số không có tính nonce nếu không được thiết kế. Đây là một điểm mù kinh điển: các giao thức cross-chain thường kiểm tra tính hợp lệ của bằng chứng, nhưng quên kiểm tra tính duy nhất của ngữ cảnh . Kinh nghiệm từ ShibeCoin năm 2017 dạy tôi: luôn bắt đầu từ validation đầu vào. BatchTransfer thiếu kiểm tra msg.value, giống hệt cách validateProof thiếu kiểm tra seqNum.
Contrarian: Phi tập trung hóa của bridge là ảo tưởng
Cộng đồng thường nói “Arbitrum Nitro là phi tập trung vì có bộ xác thực đa chữ ký”. Sai. Lỗ hổng này cho thấy phi tập trung hóa chỉ có ý nghĩa khi chữ ký được gắn với một ngữ cảnh không thể tái sử dụng. Nếu không, một tập hợp validator nhỏ có thể bị khai thác ngay cả khi chúng trung thực. Góc nhìn phản trực giác của tôi: càng nhiều validator, càng nhiều cơ hội cho kẻ tấn công nhân bản chữ ký . Một bridge với 10 validator – mỗi chữ ký là một vector tấn công tiềm năng. Lỗ hổng này không phải do validator xấu, mà do thiết kế giao thức thiếu nonce. Điều này tương tự cách “giải pháp oracle phi tập trung” của Chainlink tập trung vào node, tạo ra nghịch lý: phi tập trung hóa ở lớp vận hành, nhưng tập trung hóa ở lớp chữ ký.
Takeaway: Câu hỏi cho tương lai
Mirae Asset từng hạ mục tiêu SK Hynix vì lo ngại về “định giá đúng hơn là tăng trưởng”. Trong blockchain, bài toán tương tự: thị trường đang định giá cao các bridge dựa trên TVL và tổng giá trị bảo vệ, nhưng bỏ qua chi phí ẩn của chữ ký không nonce. Lỗ hổng Arbitrum Nitro đã được vá sau báo cáo của tôi, nhưng bao nhiêu bridge khác vẫn đang sử dụng chữ ký không nonce? Bao nhiêu giao thức Layer2 còn “phi tập trung hóa” ở cấp PowerPoint? Khi thị trường tăng, ai cũng nhìn vào APY; chỉ khi sập, họ mới nhìn vào dòng code. Tôi viết bài này không phải để khoe bounty, mà để nhắc: hãy đọc mã nguồn của bridge trước khi bridge tài sản của bạn.