Hook
Trong 48 giờ qua, một giao thức DeFi top 20 đã âm thầm vá lỗ hổng critical sau khi tôi gửi private report. Lỗi? Không phải reentrancy hay oracle manipulation. Chỉ đơn giản là một biến uint256 bị ghi đè bởi biến address trong quá trình nâng cấp proxy. Hậu quả: kẻ tấn công có thể chuyển toàn bộ số dư của pool thanh khoản sang ví mình. Tôi không ngạc nhiên. Mỗi bản nâng cấp là một cánh cửa cho lỗ hổng mới.

Context
Cơ chế proxy (EIP-1967, UUPS, hoặc Transparent Proxy) cho phép các dự án nâng cấp logic hợp đồng mà không thay đổi địa chỉ contract. Điều này tiện lợi, nhưng giống như sửa nhà khi đang ở: bạn dễ đóng đinh vào dây điện. Trong Ethereum, storage của hợp đồng được quản lý theo vị trí (slot). Proxy giữ storage cố định, trong khi implementation contract mới có thể có bố cục biến khác. Nếu slot của biến logic mới trùng với slot của biến logic cũ nhưng kiểu dữ liệu khác, storage sẽ bị hỏng. Đây gọi là storage collision.
Khung bảo mật của OpenZeppelin đã cảnh báo điều này từ năm 2020. Nhưng thực tế, tôi vẫn thấy lỗi này trong audit mỗi quý. Lý do: đội ngũ phát triển thường thêm biến mới vào giữa thay vì cuối struct, hoặc không dùng storage gap. Họ nghĩ rằng nâng cấp là an toàn vì có audit. Sai. Audit không kiểm tra toàn bộ lịch sử upgrade.
Core
Tôi phân tích một case thực tế: Giao thức X v1.0 có contract LogicV1 với storage: - Slot 0: address public owner - Slot 1: uint256 public totalSupply Khi nâng cấp lên v2.0, họ muốn thêm mapping balances. Họ viết:
