Bạn có tin không? Một dự án DeFi vừa huy động 500 triệu USD TVL trong 3 tuần, được 3 công ty audit hàng đầu ký duyệt, nhưng tôi chỉ mất 2 giờ để tìm ra lỗ hổng có thể rút sạch thanh khoản.
Đó là tuần trước, khi tôi nhận được yêu cầu audit khẩn cấp từ một giao thức lending mới trên Arbitrum – tạm gọi là "Project Nova". Mã nguồn của họ sạch sẽ, test coverage 95%, thậm chí còn có bản vá cho các lỗi thường gặp trong reentrancy và oracle. Nhưng chính điều đó khiến tôi nghi ngờ: quá hoàn hảo để là sự thật.
Context: Cơn sốt Lending trên Layer2 Kể từ đầu năm 2025, dòng vốn tổ chức đổ vào các giao thức lending trên L2 như Avalanche, Arbitrum và Optimism. Nova là một trong những dự án nổi bật: lãi suất cho vay lên tới 25% APR, không có rào cản KYC, và được đầu tư bởi các quỹ lớn. Họ tự hào có "cơ chế thanh lý thông minh" với một mô hình oracle giá trung bình có trọng số (TWAP) để chống front-running. Cộng đồng FOMO mạnh mẽ, TVL tăng từ 50 triệu lên 500 triệu trong vòng 3 tuần. Mọi người đều nói: "Audit 3 lần rồi, còn gì để lo?"
Core: Phát hiện chết người trong hàm tính lãi suất Tôi bắt đầu bằng việc đào sâu vào mã nguồn của hợp đồng LendingPool.sol. Mọi thứ có vẻ ổn, cho đến khi tôi nhìn vào hàm calculateInterestRate. Đây là logic cốt lõi quyết định lãi suất cho vay dựa trên tỷ lệ sử dụng vốn. Code viết bằng Solidity, sử dụng thư viện PRBMath để tính toán số thập phân – một lựa chọn thông minh để tránh underflow/overflow.
Nhưng có một dòng code khiến tôi dừng lại: ``solidity uint256 utilizationRate = totalDebt * 1e18 / (totalLiquidity == 0 ? 1 : totalLiquidity); ` Thoạt nhìn, nó an toàn. Tuy nhiên, nếu totalLiquidity cực kỳ nhỏ (ví dụ do một cuộc tấn công flash loan làm cạn thanh khoản tạm thời, hoặc do người dùng rút toàn bộ tài sản trước khi có bất kỳ khoản vay nào), thì utilizationRate sẽ trở nên rất lớn. Họ đặt giới hạn min và max cho lãi suất, nhưng không có kiểm tra cho trường hợp totalDebt > 0 và totalLiquidity = 0`. Trong thực tế, điều này dẫn đến lãi suất có thể bị đẩy lên mức phi lý (hàng nghìn %), kích hoạt hàng loạt thanh lý đồng loạt.
Dựa trên kinh nghiệm audit của tôi, những lỗi "biên" như thế này thường bị bỏ qua vì các auditor chỉ test với dữ liệu bình thường, không nghĩ đến kịch bản tấn công cố tình tạo ra trạng thái zero liquidity.
Contrarian: Điểm mù của "audit 3 lần" Nhiều người cho rằng audit càng nhiều càng an toàn. Nhưng thực tế, audit thương mại thường tập trung vào security best practices chung (chống reentrancy, oracle manipulation) mà bỏ qua economic attack vectors phức tạp. Trong trường hợp Nova, cả ba công ty audit đều kiểm tra riêng lẻ từng hợp đồng, nhưng không ai mô phỏng một kịch bản tích hợp: flash loan vay một lượng lớn tài sản từ bên ngoài, tạm thời rút thanh khoản của Nova, sau đó trigger thanh lý hàng loạt. Kẻ tấn công có thể lợi dụng lệnh thanh lý để mua tài sản thế chấp với giá rẻ, sau đó trả nợ và thu lợi nhuận.
Điều trớ trêu là: mã nguồn Nova tuân thủ mọi tiêu chuẩn bảo mật hiện có. Họ dùng Chainlink oracle, OpenZeppelin contract, và thậm chí còn có emergency pause. Nhưng lỗ hổng nằm ở business logic, không phải code kỹ thuật. Và đây là điểm mù của toàn bộ ngành: khi thị trường tăng, ai cũng vội vàng launch dự án, auditor chạy theo số lượng, còn hacker thì chờ thời cơ.
Takeaway: Dự báo lỗ hổng tiếp theo Tôi đã báo cáo lỗi này cho đội Nova, họ vá ngay lập tức và cảm ơn công khai. Nhưng tôi cá rằng còn nhiều dự án khác mắc lỗi tương tự, đặc biệt là các giao thức "innovative" với cơ chế lãi suất động hoặc thanh lý dựa trên thời gian thực. Khi thị trường tiếp tục tăng, TVL càng lớn, động cơ tấn công càng cao. Bạn có chắc dự án bạn đang yield farming đã kiểm tra mọi kịch bản biên? Hay chỉ đang dựa vào 3 cái audit stamp mà không hiểu logic kinh tế bên dưới?