Skip to content
GradioGHSA-h3h8-3v2v-rg7m

Gradio: Mocked OAuth Login Exposes Server Credentials and Uses Hardcoded Session Secret

Low0.0CVE-2026-27167 · Published Mar 1, 2026 · updated Jun 5, 2026

GitHub advisory

Affected versions

PackageAffectedFixed in
gradio
PyPI
>= 4.16.0, < 6.6.06.6.0
Details and references

## 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, # <-- real HF token from server ... } ``` ### 2. Hardcoded session signing secret The `SessionMiddleware` secret is derived from `OAUTH_CLIENT_SECRET` (line 50): ```python session_secret = (OAUTH_CLIENT_SECRET or "") + "-v4" ``` When running outside a Space, `OAUTH_CLIENT_SECRET` is not set, so the secret becomes the **constant string `"-v4"`**, hashed with SHA-256. Since this value is public (hardcoded in source code), any attacker can decode the session cookie payload without needing to break the signature. In practice, Starlette's `SessionMiddleware` stores the session data as **plaintext base64** in the cookie , the signature only provides integrity, not confidentiality. The token is readable by simply base64-decoding the cookie payload. ## Attack Scenario ### Prerequisites - A Gradio app using OAuth components (`gr.LoginButton`, `gr.OAuthProfile`, etc.) - The app is network-accessible (e.g. `server_name="0.0.0.0"`, `share=True`, port forwarding, etc.) - The host machine has a Hugging Face token configured - `OAUTH_CLIENT_SECRET` is **not** set (default outside of Spaces) ### Steps 1. Attacker sends a GET request to `http://<target>: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

CVSS 3.1
CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:N/I:N/A:N
Severity from
GitHub (reviewed advisory)
Weakness
CWE-522, CWE-798
Also known as
CVE-2026-27167, PYSEC-2026-63

More Gradio advisories

All Gradio

Critical advisories by email

Wednesdays: the week’s critical and high advisories in the AI and data stack, with the fixed versions. Only in weeks that have some.

Double opt-in. Unsubscribe any time.