- Một click vào link của attacker là đủ để rút ra access token production 24 giờ + refresh token 14 ngày — không cần phishing page.
- Ba lỗi chained (open DCR + thiếu redirect_uri validation + PKCE không bảo vệ initiator) đang phơi mặt trên hàng loạt MCP OAuth proxy.
TL;DR
Researcher H4cktus vừa công bố một chain 1-click full account takeover trên một MCP (Model Context Protocol) OAuth proxy production. Nạn nhân click link, đăng nhập ngay trên SSO thật, domain thật, cert thật, MFA thật — và attacker nhận về access token 24 giờ + refresh token 14 ngày. Không phishing page, không social engineering. Root cause: ba lỗi OAuth chained lại — open DCR, thiếu redirect_uri validation, và PKCE được thiết kế để bảo vệ client khởi tạo flow, không bảo vệ nạn nhân. Cùng lúc, Obsidian Security xác nhận pattern này đang tồn tại trên Square MCP, Wix MCP và phần lớn remote MCP server được khảo sát.
Chuyện gì vừa xảy ra
H4cktus công bố bài phân tích tại hackt.us kèm recon checklist để soi lỗi tương tự trên các MCP proxy khác. Đây là bug class đi theo làn sóng bùng nổ remote MCP server kể từ nửa cuối 2025: nhiều MCP server vừa đóng vai AS (authorization server) cho MCP client, vừa đóng vai OAuth client tới SaaS upstream. Hai tầng OAuth chồng lên nhau, bề mặt implementation rộng — và dễ sai.
Song song, Obsidian Security phát hành báo cáo industry (29/01/2026) cho thấy cùng pattern này đã dính trên Square MCP (mcp.squareup.com) và Wix MCP, với chỉ 3 trên 78 MCP authorization server họ khảo sát có support CIMD — giải pháp thay thế cho open DCR.
Vì sao đáng lo
Cú hack này không cần attacker host gì cả. Không có fake login page để browser cảnh báo. Nạn nhân chỉ thấy đúng màn hình SSO mà họ vẫn dùng hằng ngày. Trong bối cảnh mỗi AI assistant (Claude Desktop, Cursor, VS Code MCP client...) kết nối ngày càng nhiều remote MCP server thay cho user, một cú click trong chat hoặc email là đủ để attacker có quyền gọi API thay user trong 14 ngày. Trên MCP server kết nối vào billing (Square), CMS (Wix), ticketing (Atlassian) — thiệt hại không dừng lại ở read-only.
Ba lỗi trong chain
1. Open Dynamic Client Registration (DCR)
Endpoint /register của MCP proxy chấp nhận đăng ký bất kỳ client nào, không allowlist. Attacker đăng ký một client mới với redirect_uri trỏ về chính mình.
2. Thiếu redirect_uri validation
Proxy không strict-match redirect_uri với mẫu đã được pre-approve khi chạy authorization. Redirect do attacker cài sẵn được chấp nhận nguyên văn.
3. PKCE không bảo vệ initiator
Đây là twist quan trọng nhất. PKCE (RFC 7636) được thiết kế để bảo vệ client khởi tạo flow khỏi bị chặn authorization code. Giả định ngầm: client khởi tạo = bên hợp pháp. Trong tấn công này, attacker chính là bên khởi tạo: họ sinh code_verifier, start flow, rồi gửi cho nạn nhân URL /authorize. Nạn nhân đăng nhập thật, authorization code quay về redirect_uri do attacker cài. Attacker — người giữ code_verifier — đổi code lấy token. PKCE bind code với verifier, nó không bind flow với browser session của nạn nhân.
Attack flow tóm gọn
- Attacker gọi DCR, đăng ký client mới với
redirect_uricủa mình. - Attacker sinh
code_verifier+code_challenge, build URL/authorize. - Attacker tự click qua consent của MCP proxy (nếu có), capture URL redirect tới SSO upstream.
- Gửi URL đó cho nạn nhân (DM, email, chat trong AI assistant...).
- Nạn nhân click, đăng nhập SSO thật + MFA thật. SSO thường cache consent theo
client_id, nên không hỏi lại. - Authorization code redirect về server attacker.
- Attacker token-exchange với
code_verifierđã lưu → nhận access token 24h + refresh token 14d.
So với các bug OAuth kinh điển
| Phòng thủ | Bảo vệ ai | Hiệu quả ở đây |
|---|---|---|
| State parameter bind session | Nạn nhân (chống CSRF) | ❌ MCP proxy không bind state với session cookie |
| Fake login phishing check | Nạn nhân | ❌ Không có fake page, SSO thật 100% |
| PKCE (RFC 7636) | Client khởi tạo flow | ❌ Attacker chính là initiator |
| Strict redirect_uri allowlist | Toàn flow | ✅ Nếu có — nhưng proxy thiếu |
| CIMD thay DCR | Toàn flow | ✅ Khuyến nghị MCP spec — adoption <4% |
Recon checklist soi MCP proxy khác
Tổng hợp từ bài của H4cktus và pattern Obsidian Security công bố, khi audit một remote MCP server bạn nên check:
- Có expose
/register(DCR) public không? Có acceptredirect_uritùy ý không? - Khi chạy
/authorize, proxy có strict-matchredirect_urivới mẫu đã đăng ký không? - MCP server và upstream OAuth client có chung
client_idkhông? Nếu có → upstream AS sẽ cache consent, bypass MCP consent. - State cookie có
__Host-prefix +HttpOnly+SameSite=Laxkhông? - Consent screen của MCP có hiển thị rõ
client_idđang đăng ký vàredirect_urithật không? - Server có support CIMD hay vẫn chạy open DCR?
- Fix redirect_uri validation có áp dụng lên client cũ đã đăng ký, hay chỉ cho client mới?
Vá lỗi & tình trạng hiện tại
Square và Wix đã ship fix cuối tháng 9/2025. MCP spec update ngày 25/11/2025 thêm hướng dẫn consent flow, state binding, redirect_uri validation và khuyến nghị CIMD. Tuy nhiên, theo khảo sát của Obsidian, đa số remote MCP server vẫn dính ít nhất một trong ba lỗi tính đến cuối 2025. Đặc biệt, server nào chỉ fix forward (áp dụng cho client đăng ký mới) thì client đã đăng ký trước fix vẫn có thể exploit được. Không có CVE công khai, bounty amount không được disclosure.
Bước tiếp theo
Nếu bạn đang vận hành MCP server: audit theo checklist trên, chuyển sang CIMD khi khả thi, bind state với session cookie dùng __Host- prefix, hiển thị consent rõ ràng ở MCP layer. Nếu là user AI assistant: cảnh giác với link /authorize lạ trong chat — kể cả link trỏ thẳng vào SSO thật cũng có thể là bẫy. Nếu là bug-bounty hunter: recon checklist đã mở, long tail MCP server còn rất lớn.
Nguồn: hackt.us, Obsidian Security, MCP Authorization spec.
