VAITP Dataset

← Back to the dataset

CVE-2026-27167

Gradio's mocked OAuth leaks the server's Hugging Face access token.

  • CVSS 5.9
  • CWE-522
  • Authentication, Authorization, and Session Management
  • Remote

Gradio is an open-source Python package designed for quick prototyping. Starting in version 4.16.0 and prior to version 6.6.0, 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. Version 6.6.0 fixes the issue.

CVSS base score
5.9
Published
2026-02-27
OWASP
A07 Identification and Authentication Failures
Orthogonal defect classification
Checking
Code defect classification
Incorrect Algorithm
Category
Authentication, Authorization, and Session Management
Subcategory
Insecure Handling of Sensitive Data
Accessibility scope
Remote
Impact
Information Disclosure
Affected component
Gradio
Fixed by upgrading
Yes

Solution

Upgrade Gradio to version 6.6.0 or later.

Vulnerable code sample

import gradio as gr

# This code requires a vulnerable version of Gradio (e.g., 4.16.0 <= version < 6.6.0)
# and for the server environment to be logged into the Hugging Face Hub.

with gr.Blocks() as demo:
    gr.Markdown("A simple Gradio application with an OAuth component.")
    gr.LoginButton()

demo.launch()

Patched code sample

# This code is a simplified representation of the fix for CVE-2024-27167,
# based on the changes made in the Gradio source code (e.g., in gradio/routes.py).
# The vulnerability was that a "mocked" OAuth flow, intended for local development,
# was enabled by default on self-hosted applications. This flow exposed the
# server's Hugging Face token to any remote user.

# The fix introduces a new parameter, `enable_mocked_oauth`, which defaults
# to False. This ensures the vulnerable code path is not accessible unless
# a developer explicitly opts in for local testing purposes.

from typing import Optional
from fastapi import Request, Response
from huggingface_hub import utils as hf_hub_utils


# A simplified representation of the Gradio App class structure
class App:
    def __init__(
        self,
        space_id: Optional[str] = None,
        # THE FIX: A new parameter `enable_mocked_oauth` is introduced, defaulting to `False`.
        # This disables the vulnerable mocked OAuth flow by default for self-hosted apps.
        enable_mocked_oauth: bool = False,
        # ... other parameters
    ):
        self.space_id = space_id
        self.enable_mocked_oauth = enable_mocked_oauth
        # ... other initializations

        # In the original code, the logic to add routes is here.
        # The fix ensures these routes are only added if running on Hugging Face Spaces
        # (self.space_id is not None) OR if the developer explicitly enables the mock flow.
        if self.enable_mocked_oauth or self.space_id:
            # In a real app, this would add the route:
            # self.add_api_route("/login/huggingface", self.login_huggingface, methods=["GET"])
            pass

    async def login_huggingface(self, request: Request) -> Response:
        """
        This method handles the Hugging Face login flow.
        The fix is demonstrated in the `if not self.space_id:` block.
        """
        # If running on a Hugging Face Space, the real (secure) OAuth flow is used.
        # This part of the logic was not the source of the vulnerability.
        if self.space_id:
            # ... code for the real OAuth flow on Hugging Face Spaces ...
            return Response("Redirecting to real Hugging Face OAuth...", status_code=302)

        # This block handles the "mocked" login for self-hosted apps.
        # This is where the vulnerability existed and was fixed.
        if not self.space_id:
            # THE FIX: This condition now checks the `enable_mocked_oauth` flag.
            # If it's False (the default), it returns a 404 Not Found error,
            # preventing access to the vulnerable logic.
            if not self.enable_mocked_oauth:
                return Response(
                    content="Mocked OAuth is disabled. Set `enable_mocked_oauth=True` in `gr.Blocks()` to enable.",
                    status_code=404,
                )

            # This vulnerable code block is now only reachable if a developer
            # has explicitly set `enable_mocked_oauth=True` for local testing.
            #
            # Previously, this block would execute unconditionally for any
            # self-hosted Gradio app using an OAuth component.
            try:
                # Step that caused the vulnerability: getting the SERVER's token.
                token = hf_hub_utils.get_token()
                if token is None:
                    return Response("Server not logged in to Hugging Face Hub", status_code=500)
            except hf_hub_utils.HfHubLoginError:
                return Response("Server not logged in to Hugging Face Hub", status_code=500)

            # Step that caused the vulnerability: setting the server's token
            # in the VISITOR's session cookie.
            response = Response(status_code=302, headers={"Location": "/"})
            response.set_cookie(key="access-token-unsecure", value=token)
            return response

        return Response("This code path should not be reached.", status_code=500)

Cite this entry

@misc{vaitp:cve202627167,
  title        = {{Gradio's mocked OAuth leaks the server's Hugging Face access token.}},
  author       = {Bogaerts, Fr\'ed\'eric and Ivaki, Naghmeh and Fonseca, Jos\'e},
  year         = {2026},
  note         = {VAITP Python Vulnerability Dataset, entry CVE-2026-27167},
  howpublished = {\url{https://netpack.pt/vaitp/vulnerability/CVE-2026-27167/}}
}
Introducing the "VAITP dataset": a specialized repository of Python vulnerabilities and patches, meticulously compiled for the use of the security research community. As Python's prominence grows, understanding and addressing potential security vulnerabilities become crucial. Crafted by and for the cybersecurity community, this dataset offers a valuable resource for researchers, analysts, and developers to analyze and mitigate the security risks associated with Python. Through the comprehensive exploration of vulnerabilities and corresponding patches, the VAITP dataset fosters a safer and more resilient Python ecosystem, encouraging collaborative advancements in programming security.

The supreme art of war is to subdue the enemy without fighting.

Sun Tzu – “The Art of War”

:: Shaping the future through research and ingenuity ::