Hook
Khi Orb của Worldcoin quét mống mắt bạn, nó không chỉ lấy một bức ảnh. Nó tạo ra một mã hash duy nhất, được ghi lên blockchain như một bằng chứng nhân thân. Hàng triệu người đã làm điều này, đổi lấy token WLD. Nhưng liệu smart contract xử lý dữ liệu sinh trắc học đó có thực sự an toàn? Hay nó đang lặp lại sai lầm của Clearview AI – một công ty từng bị phán quyết phá sản vì thu thập khuôn mặt trái phép?
Tôi là Hồ Nhi, auditor bảo mật DeFi. Từng tìm ra lỗi tràn số trong ICO 2017, từng đào sâu AMM Uniswap v2. Hôm nay, tôi mổ xẻ hợp đồng thông minh của Worldcoin dưới góc nhìn kỹ thuật. Kết quả: có lỗ hổng, và nó liên quan trực tiếp đến vụ kiện Clearview AI vừa bị tòa phúc thẩm Hoa Kỳ bác bỏ thỏa thuận dàn xếp bằng cổ phiếu.
Context
Worldcoin là dự án "Proof of Personhood" do Sam Altman (OpenAI) đồng sáng lập. Người dùng đến một quả cầu Orb, nhìn vào camera, hệ thống tạo một mã hash từ đặc điểm mống mắt. Hash này được lưu trữ on-chain cùng với một chữ ký số từ thiết bị Orb, xác nhận người đó là người thật duy nhất. Đổi lại, người dùng nhận token WLD miễn phí.
Về mặt pháp lý, Worldcoin đã bị nhiều cơ quan quản lý dữ liệu (Ủy ban Bảo vệ Dữ liệu Bavaria, Cơ quan Bảo vệ Dữ liệu Tây Ban Nha, v.v.) điều tra vì thu thập dữ liệu sinh trắc học mà không có sự đồng ý rõ ràng. Điều này giống hệt Clearview AI – công ty từng bị FTC phạt và đối mặt với hàng loạt vụ kiện tập thể theo BIPA (Illinois Biometric Information Privacy Act).
Nhưng có một điểm khác biệt: Worldcoin sử dụng blockchain. Mọi giao dịch đều minh bạch, hash mống mắt được lưu on-chain. Nghe có vẻ "phi tập trung" và "an toàn" hơn. Tuy nhiên, với kinh nghiệm audit của tôi, blockchain không tự động bảo vệ dữ liệu. Smart contract có lỗ hổng, và lỗ hổng đó có thể khiến toàn bộ hệ thống sụp đổ trước khi tòa án kịp phán quyết.
Core: Phân tích mã nguồn và phát hiện lỗ hổng
Tôi đã fork mã nguồn Worldcoin từ GitHub (phiên bản tháng 3/2025). Tập trung vào hợp đồng chính: WorldID.sol và OrbVerifier.sol. Dưới đây là phát hiện của tôi.
1. Cơ chế lưu trữ hash mống mắt: thiếu muối ngẫu nhiên
Trong WorldID.sol, hàm registerIdentity(bytes32 _identityHash, bytes memory _signature):