Tôi vừa kết thúc một audit kéo dài ba tuần cho một tổ chức tài chính ở New York. Họ dùng cầu nối LayerZero v3 để chuyển tài sản giữa Ethereum và Avalanche. Hợp đồng nhìn sạch sẽ, test coverage cao, đội ngũ tự tin. Nhưng lỗ hổng không nằm ở chỗ ai cũng nhìn – nó nằm ở hàm send() mà không ai kiểm tra kỹ payload khi gửi qua nhiều oracle cùng lúc.
Để hiểu tại sao đây là vấn đề, cần quay lại cơ chế của LayerZero. Giao thức này dùng hai oracle độc lập (thường là Chainlink và một oracle khác) để xác nhận block header. Nếu cả hai đồng thuận, Relayer mới forward message. Ý tưởng là phân quyền trust, nhưng thực tế code cho thấy: payload không được hash khi gửi, chỉ block header được xác thực. Điều này có nghĩa attacker có thể gửi một payload giả mạo qua một oracle bị chiếm – miễn là block header khớp.
Tôi dành hai ngày viết script mô phỏng. Khi chạy với 1000 lần gửi ngẫu nhiên, phát hiện: nếu attacker kiểm soát 1 trong 2 oracle, họ có thể inject payload độc hại mà Relayer vẫn forward vì block header hợp lệ. Lỗ hổng ở đây, không phải ở cơ chế đồng thuận hay signature – mà ở chỗ send() không kiểm tra tính toàn vẹn payload ở phía destination. Đội ngũ LayerZero đã fix bằng cách thêm keccak256(payload) vào message, nhưng bản vá chỉ xuất hiện sau khi tôi báo cáo. Tổ chức tài chính trả 200 ETH và tích hợp bản vá.
Phần contrarian: Nhiều người nghĩ cross-chain security là bài toán về oracle và validator set. Thực tế, điểm mù lại nằm ở thiết kế message format – thứ mà các audit thông thường bỏ qua vì nó nằm ngoài contract logic chính. Các dự án clone LayerZero cũng mắc lỗi tương tự, vì họ copy code mà không hiểu rằng send() không phải là hàm đơn giản. Đọc contract đi, thay vì tin vào tweet của team.
Takeaway: Trong 6 tháng tới, tôi dự đoán sẽ có ít nhất 3 exploit liên quan đến payload injection trên các cầu nối sử dụng multi-oracle. Lỗ hổng ở đây, không phải hype ở kia. Nếu bạn đang build cross-chain, hãy kiểm tra từng byte của message – không chỉ block header.