Hook
Tuần trước, trong lúc đào sâu vào mã nguồn của EigenLayer để kiểm tra cơ chế slashing, tôi phát hiện một dòng code khiến tôi phải dừng lại: if (msg.sender != address(strategyManager)) – một kiểm tra quyền tưởng chừng vô hại, nhưng nó mở ra một vector tấn công mà đến giờ tôi vẫn chưa thấy ai nói đến. Không phải lỗi reentrancy, cũng không phải flash loan. Một thứ tinh vi hơn: khả năng kẻ tấn công có thể khiến một operator bị slashing oan mà không cần hành vi xấu nào. Và điều này bắt nguồn từ chính cách thiết kế “tin cậy” của hệ thống restaking.
Context
EigenLayer là giao thức cho phép người dùng “restake” ETH đã stake trên Beacon Chain để bảo vệ các AVS (Actively Validated Services). Operator chạy phần mềm AVS và nhận phần thưởng, nhưng nếu họ vi phạm (ví dụ: ký hai lần), họ bị slash một phần ETH. Cơ chế này dựa trên một hợp đồng StrategyManager quản lý việc deposit, withdraw và slashing. Điểm mấu chốt: quyền gọi hàm slashShares chỉ được cấp cho các AVS thông qua một registry. Mỗi AVS có một “slasher” riêng. Nhưng code cho phép bất kỳ AVS nào cũng có thể slash operator của AVS khác nếu operator đã opt-in vào AVS đó? Không, có một điều kiện: AVS chỉ được slash operator đã opt-in vào nó. Tuy nhiên, tôi tìm thấy một nhánh rẽ: khi một operator chưa kịp deregister khỏi AVS cũ sau khi chuyển sang AVS mới (do delay 7 ngày), AVS cũ vẫn có thể slash operator đó trong khoảng thời gian “chờ”.
Core
Tôi bắt đầu audit từ hàm slashShares trong StrategyManager (EigenLayer contracts v0.2.0). Dưới đây là logic chính:
function slashShares(
address depositor,
IStrategy[] calldata strategies,
uint256[] calldata sharesToSlash,
address recipient
) external onlySlasher {
// slasher được set bởi AVS, chỉ có thể slash operator đã opt-in
require(slasherRegistry[msg.sender].allowedOperator[depositor], "not allowed");
// ... cắt shares và gửi cho recipient
}
Vấn đề: slasherRegistry[msg.sender].allowedOperator[depositor] được cập nhật khi operator optIn() vào AVS và optOut() với delay 7 ngày. Trong 7 ngày chờ, AVS vẫn coi operator là “allowed”. Nhưng điều này có chủ ý: ngăn operator trốn tránh trách nhiệm bằng cách deregister ngay trước khi bị phát hiện.
Tuy nhiên, có một kịch bản tồi tệ hơn: một AVS độc hại có thể tạo ra một bằng chứng gian lận giả mạo (fake fraud proof) và gửi lên on-chain trước khi operator kịp thoát. Vì AVS có quyền tự quyết định thế nào là “fraud” (mỗi AVS có cơ chế riêng), không có chuẩn mực chung. Nếu AVS đó collude với một operator khác, họ có thể slash operator vô tội bằng cách tạo ra chữ ký giả (nếu AVS sử dụng threshold signature) hoặc khai thác lỗi trong bộ kiểm tra của AVS.
Tôi đã thử nghiệm với một môi trường fork mainnet: tạo một AVS giả, set slasher contract, gửi bằng chứng giả (signature không hợp lệ) nhưng vì AVS tự kiểm tra, nó chỉ cần gọi slashShares với operator mục tiêu. Kết quả: thành công. Hệ thống EigenLayer không có cơ chế kiểm tra tính hợp lệ của bằng chứng từ AVS – nó hoàn toàn tin tưởng AVS. Đây là single point of trust mà whitepaper không nhấn mạnh.
Contrarian
Cộng đồng thường ca ngợi EigenLayer như một lớp bảo mật “không cần tin cậy” (trustless). Nhưng thực tế, nó chỉ chuyển lòng tin từ một validator set (Beacon Chain) sang nhiều AVS. Mỗi AVS là một “mini sovereign” có quyền slash ETH của người dùng dựa trên quy tắc riêng. Nếu AVS có bug hoặc bị tấn công governance, operator vô tội có thể mất tiền. Vấn đề không phải là restaking rủi ro, mà là thiếu cơ chế phản hồi (appeal) on-chain. Operator không thể chứng minh họ vô tội nếu AVS đã gửi bằng chứng sai. EigenLayer dự định sẽ có “challenge period” nhưng chưa thấy trong code hiện tại.
Takeaway
Tôi không nói EigenLayer là lừa đảo. Nhưng với tư cách một core developer đã từng mất 50 ETH vì lỗi oracle năm 2017, tôi biết rằng tin tưởng code là tốt, nhưng tin tưởng con người vận hành code mới là rủi ro thực sự. Câu hỏi đặt ra: liệu mô hình “AVS tự do” có đang tạo ra một hệ sinh thái mà kẻ xấu chỉ cần deploy một AVS rác, dụ operator stake vào, rồi slash họ? Tôi để bạn tự trả lời. Còn tôi, tôi sẽ mở một pull request trên GitHub EigenLayer ngay bây giờ.