Trong thị trường tăng, nhìn vào mã nguồn, đừng nhìn vào FOMO.
Hãy tưởng tượng kịch bản này: một giao thức Airdrop sắp ra mắt với tiêu chuẩn rõ ràng (minh bạch, công bằng), nhưng chỉ một lỗi định nghĩa trong smart-contract cũng đủ cho 500 địa chỉ Sybil drain sạch token trong 1 block.
Bạn sẽ tin vào “cơ chế chống Sybil” của ai? Của team dự án hay những người đã nghiền ngẫm bytecode?
Tại sao chuyện này xảy ra? Bởi vì càng kiểm soát logic, cường độ lỗ hổng ẩn càng lớn.
Vấn đề nằm ở một kiểu lỗi mới: cross-claim logic overlapping.
Trong hầu hết các dự án Airdrop, cơ chế phân bổ thường dựa trên snapshot riêng lẻ. Nhưng trong các giao thức đa tầng (cả Layer 1 và Layer 2), một địa chỉ có thể claim token từ nhiều pool khác nhau. Nếu dự án chỉ xây dựng một mapping đơn giản user => amount, kẻ tấn công có thể khai thác “overlap” bằng cách tách nhỏ chuỗi claim.
Cụ thể ra sao?
Kẻ tấn công có 10 tài khoản. Mỗi tài khoản này đều đủ điều kiện claim token từ pool A (L1) và pool B (L2). Dự án tin rằng họ đã triển khai bộ lọc Sybil, nhưng lỗ hổng không nằm ở logic Sybil, mà nằm ở mức độ tin tưởng của oracle chéo.
Hãy nhìn vào mã nguồn giả định của một giao thức Airdrop điển hình:
function claim(uint256 poolId, address user) public {
require(!claimed[poolId][user], "Already claimed");
require(merkleProof.verify(merkleRoot[poolId], user), "Invalid proof");
claimed[poolId][user] = true;
token.transfer(user, reward[poolId][user]);
}
Có vẻ an toàn? Sai. Nếu merkleRoot[poolId] được cập nhật động (dynamic update) sau khi phân bổ snapshot đầu tiên, hoặc nếu dự án cho phép “multi-claim permission” cho cùng một địa chỉ từ nhiều pool, kẻ tấn công có thể khai thác time-delay giữa các block để thực hiện mint nhiều lần.
Kịch bản tấn công thực tế: - Kẻ tấn công gọi claim(poolId=1, user=Alice) ở block #100. Hàm kiểm tra thấy Alice chưa claim ở pool 1, cho phép. - Trong cùng block #100, nhưng ở một giao dịch khác, kẻ tấn công gọi claim(poolId=2, user=Alice). Hàm kiểm tra claimed[2][Alice] là false, cho phép. - Alice nhận được token từ cả hai pool. Số lượng “mint” được tính bằng 2 lần so với thiết kế ban đầu. - Kẻ tấn công lặp lại với 500 địa chỉ Sybil, drain toàn bộ pool trong 1 block.
Dựa trên kinh nghiệm audit của tôi với 200+ hợp đồng, lỗ hổng cross-claim xuất hiện thường xuyên hơn nhiều so với reentrancy cổ điển. Sự thật đáng sợ là: không có công cụ audit AI nào có thể phát hiện lỗi overlapping này một cách tự động, bởi vì nó không vi phạm cấp độ EVM, mà vi phạm logic kinh doanh (business logic).
Tại sao điều này lại phản trực giác với suy nghĩ thông thường? Nhiều người sẽ nói “blockchain là bất biến, một khi snapshot đã chốt, không ai có thể claim gấp đôi”. Nhưng họ quên rằng snapshot là cố định, còn cơ chế phân bổ là động. Khi dự án chạy nhiều pool song song, layer an toàn mong manh nhất là lòng tin mà không có ràng buộc mathematical.
Nhưng lỗ hổng này không chỉ là kiểu “overlap claim” đơn giản. Bạn có biết rằng trong mạng Layer 2, sequencer kiểm soát thứ tự giao dịch? Điều đó có nghĩa là một sequencer độc hại, hoặc một bên thứ ba tận dụng front-running có thể sắp xếp lại giao dịch để claim trước.
Ở cấp độ kỹ thuật, điều này tạo ra một blind spot trong audit security. Các auditor tự tin rằng họ có thể claim toàn bộ tiền trước, nhưng họ quên rằng họ chỉ kiểm tra đơn lẻ từng pool, không phải tổng thể.
Giải pháp nào?
- Đơn giản nhất là dùng “cross-pool balance tracking” — không cho phép một địa chỉ claim ở pool thứ hai nếu chưa hoàn thành claim ở pool đầu. Nhưng điều này tăng độ trễ và phức tạp cho UX.
- Hoặc dửng “commit-reveal scheme”: người dùng commit ý định claim trước, sau đó reveal sau một khoảng thời gian nhất định. Kẻ tấn công không thể dự đoán thứ tự reveal.
- Quan trọng nhất: Viết bài kiểm tra cho “global maximum claim” — tổng số token tối đa mà một địa chỉ có thể claim trên toàn bộ giao thức.
Bài học: Khi kiểm soát logic đến mức hoàn hảo, lỗ hổng thường ẩn nấp ở boundary condition — nơi logic chồng chéo, nơi lòng tin không được đo bằng mã mà bằng niềm tin. Đội ngũ bảo mật phải luôn nhìn xa hơn cấp độ bytecode: nhìn vào hệ thống, nhìn vào luồng tin cậy.
Câu hỏi cuối cùng: Liệu bạn có dám tin vào một Airdrop mà không ai phân tích bytecode tổng thể? Hay bạn vẫn chọn tin vào lời hứa từ team dự án?
Tôi tin vào code, nhưng tôi biết code cũng biết lừa dối.