- Phiên bản gốc của plugin Sign-In with Ethereum cho Discourse lấy danh tính người dùng từ một trường form client-controlled thay vì từ chữ ký SIWE đã verify.
- Hậu quả: suốt 3+ năm, bất kỳ ai cũng có thể đăng nhập thành bất kỳ ai.
- Bug vừa được công bố ngày 20/04/2026 cùng 3 lỗ hổng khác, đã fix trong bản rewrite mới.
- ENS và các forum hệ sinh thái đã migrate.
TL;DR
Ngày 20/04/2026, đội SIWE công bố 4 lỗ hổng bảo mật trong plugin spruceid/discourse-siwe-auth — plugin Sign-In with Ethereum chính thức cho Discourse — đã tồn tại hơn 3 năm trong production. Nghiêm trọng nhất là một lỗi authentication bypass hoàn toàn: server đọc danh tính Ethereum từ một trường form ẩn do client gửi, thay vì từ địa chỉ đã được chữ ký SIWE verify. Kẻ tấn công chỉ cần ký bằng ví của mình rồi đổi trường form sang địa chỉ nạn nhân là login được luôn. Bản rewrite signinwithethereum/discourse-siwe-auth v1.1.0+ đã fix toàn bộ. ENS DAO forum và các forum hệ sinh thái đã migrate; người dùng cần reconnect ví.
Công bố có gì
Bug được phát hiện trong lúc đội SIWE đang viết lại plugin tháng trước, không phải qua audit hay bug bounty. Sau 30 ngày embargo (thông báo upgrade ngày 20/03/2026 trên forum ENS), chi tiết kỹ thuật được công khai vào 20/04/2026.
Bốn vấn đề được liệt kê theo mức độ:
- Critical — Account takeover qua trường form chưa verify.
- High — Key account bằng ENS name thay vì địa chỉ Ethereum.
- Medium — Nonce replay trong phiên.
- Medium — Dữ liệu hiển thị (ENS name, avatar) do client tự submit, không verify.
Tính tới thời điểm công bố, chưa có CVE được gán. Không có PoC public — bản vá đã ra và các forum lớn đã migrate trước.
Vì sao đáng lưu tâm
Đây là lớp xác thực của một plugin được recommend chính thức bởi docs login.xyz, dùng cho các forum quản trị DAO — nơi phiếu bầu và danh tính on-chain có giá trị thật. Việc bất kỳ ai cũng có thể đăng nhập thành bất kỳ ai suốt 3+ năm đồng nghĩa với: mọi tài khoản forum từng link SIWE đều nằm trong diện giả định đã bị lộ. Đáng nói là bug không phức tạp về mặt crypto — chỉ là một lỗi rất cổ điển: tin vào dữ liệu client gửi lên.
Câu hỏi khó chịu: tại sao hơn 3 năm không ai phát hiện? Plugin open source, code public, đã tích hợp vào nhiều forum DAO có TVL lớn. Cảnh báo chung cho bất kỳ luồng auth nào có chữ ký: địa chỉ phải luôn được derive từ signature verify được server-side, không bao giờ đọc từ field do client submit song song.
Chi tiết kỹ thuật 4 lỗi
1. Critical — Account takeover qua eth_account form field
Server cũ đọc địa chỉ người dùng từ một trường form ẩn tên eth_account do client gửi, thay vì từ siwe_message.address đã được chữ ký verify. Kịch bản tấn công:
- Attacker ký SIWE message hợp lệ bằng ví của chính họ.
- Trước khi submit, attacker sửa trường
eth_accountthành địa chỉ của nạn nhân. - Server verify chữ ký (pass, vì ký bằng ví attacker), rồi tra account bằng
eth_account(địa chỉ nạn nhân) — login thành công với phiên của nạn nhân.
Fix: bỏ hoàn toàn field identity do client submit, UID luôn derive từ siwe_message.address đã verify.
2. High — Key account bằng ENS name
Plugin link account Discourse với ENS name chứ không phải địa chỉ Ethereum thô. Khi một domain ENS đổi chủ (bán, hết hạn, transfer), chủ mới tự động inherit tài khoản forum của chủ cũ. Fix: UID là raw address; ENS name resolve server-side và forward-verify (resolve tên → ra address → so với address hiện tại).
3. Medium — Nonce replay
Nonce trong session không bị xoá sau khi dùng, cho phép replay chữ ký trong cùng phiên. Fix một dòng Ruby: session.delete(:nonce) ngay trước bước so sánh.
4. Medium — Dữ liệu hiển thị chưa verify
Client có thể submit bất kỳ ENS name và avatar URL nào cho profile. Fix: resolve server-side qua ENS Metadata Service.
So sánh plugin cũ vs mới
| Khía cạnh | Cũ spruceid/discourse-siwe-auth ≤0.1.2 | Mới signinwithethereum/discourse-siwe-auth ≥1.1.0 |
|---|---|---|
| Nguồn identity | Form field eth_account (client) | siwe_message.address đã verify |
| Key account | ENS name | Raw Ethereum address |
| Nonce | Không invalidate sau khi dùng | Xoá trước khi compare |
| Display data (ENS, avatar) | Client submit | Server resolve qua ENS Metadata |
| Maintainer | SpruceID (legacy) | SIWE team |
Ai bị ảnh hưởng
Mọi Discourse forum cài plugin SIWE phiên bản cũ — chủ yếu là các forum quản trị web3/DAO. Đã được xác nhận migrate: ENS DAO governance forum (discuss.ens.domains). Admin các forum còn lại cần coi đây là ưu tiên cao, vì một tài khoản moderator/admin bị takeover có thể kéo theo thiệt hại quản trị lớn hơn nhiều so với vote thường.
Action items cho admin & user
Admin:
- Gỡ
spruceid/discourse-siwe-auth, càisigninwithethereum/discourse-siwe-authv1.1.0+. - Config
siwe_ethereum_rpc_urltrỏ tới một RPC endpoint riêng (cần cho server-side ENS resolve). - Nếu chưa thể upgrade ngay: tạm tắt plugin qua Admin Settings → Plugins →
discourse-siwe→ uncheckdiscourse siwe enabled. - Audit log audit: tìm các phiên SIWE login bất thường từ trước tới giờ.
User:
- Sau khi admin upgrade, phải reconnect ví Ethereum trong profile settings — liên kết cũ bị invalidate.
- Review hoạt động tài khoản, đặc biệt post/vote/DM trong thời gian dài trước đó.
Tiếp theo
Legacy repo spruceid/discourse-siwe-auth coi như deprecated; nguồn chính thức mới là signinwithethereum/discourse-siwe-auth. Đội SIWE nhiều khả năng sẽ xin CVE chính thức và bổ sung security advisory. Với các dự án web3 khác đang dùng pattern auth tương tự (ví dụ SIWE plugin cho các CMS khác, tích hợp tự viết), đây là lúc nên tự audit xem mình có lặp chính xác lỗi lấy identity từ client thay vì từ signature không.
Nguồn: ENS DAO forum — disclosure post #3, spruceid/discourse-siwe-auth, Jalil Wahdat on X.