High

FastMCP OAuth Callback Reflected XSS

FastMCP versions before 2.13.0 build the OAuth callback page by inserting URL parameters directly into HTML without escaping them. An attacker who gets a victim to open a crafted callback link can run JavaScript in the victim's session, right at the moment OAuth tokens are being exchanged.

How the attack works

An attacker crafts a link to the FastMCP OAuth callback endpoint with script markup, an event-handler attribute, or a javascript:/data: URL scheme in the query string or body, possibly percent-encoded to dodge basic filters. The victim opens the link, often after fetching it from an attacker-controlled page. FastMCP reflects the unescaped parameter into the generated HTML and the browser executes it. Because this happens during an active OAuth authorize/token exchange, the injected script can intercept or exfiltrate the resulting access/refresh tokens.

Netzilo detection

Netzilo reports this behaviour when it is observed.

Signature ID
7c3f9a2e-5d41-4b8a-9e02-6f1c8d4b7a35
Severity
High

Why it matters

A successful callback injection lets an attacker steal OAuth tokens issued during the exchange, giving them the same access as the victim's authenticated session without needing credentials.

What you can do

  • Upgrade FastMCP to 2.13.0 or later, which escapes callback parameters.
  • Audit any custom OAuth callback handlers for unescaped output of query, body, or header values.
  • Restrict which redirect/callback URLs your OAuth clients accept, and reject ones containing script markup or javascript:/data: schemes.
  • Treat detections from known scanners or developer testing as expected; verify the process lineage before escalating, and investigate anything originating from an unfamiliar browser or agent session.

Known benign look-alikes

  • Authorized security testing — DAST scanners, Burp/ZAP payload replay or a red-team engineer manually probing the FastMCP callback endpoint with alert()/img-onerror payloads. These are true detections of the technique but expected activity; correlate with the reported process lineage (scanner binary vs. browser/agent) before escalating.
  • A developer working on oauth_callback.py locally and passing markup through the callback query string to verify the escaping fix. Same signature, benign intent.
  • An agent fetching an XSS write-up, CVE advisory or cheat-sheet whose URL happens to contain a "/callback" segment together with a sample payload in the query string.
  • An OAuth provider redirecting back with an error_description that contains raw angle brackets or quotes from an upstream error message. Mitigated by requiring tag names, on*= handlers, javascript:/data:text/html schemes or entity-encoded '<' rather than bare punctuation.
  • Redirect-chain or URL-shortener traffic where an encoded downstream target string resembles a script scheme. Mitigated by requiring the callback-shaped path on the triggering request itself.

References