PrefectHQ/fastmcp · error · CIMDValidationError
CIMD jwks_uri failed SSRF validation: {e}
Error message
CIMD jwks_uri failed SSRF validation: {e} What it means
When the CIMD document declares a jwks_uri, fetch() applies the same SSRF validation to that JWKS URL as to the client_id URL. If validate_url raises SSRFError (private IP, blocked scheme, DNS pinning failure), the error is wrapped in CIMDValidationError so a hostile document cannot make the server fetch internal endpoints.
Source
Thrown at fastmcp_slim/fastmcp/server/auth/cimd.py:429
try:
doc = CIMDDocument.model_validate(data)
except Exception as e:
raise CIMDValidationError(f"Invalid CIMD document: {e}") from e
if str(doc.client_id).rstrip("/") != client_id_url.rstrip("/"):
raise CIMDValidationError(
f"CIMD client_id mismatch: document says '{doc.client_id}' "
f"but was fetched from '{client_id_url}'"
)
# Validate jwks_uri if present (SSRF check for JWKS endpoint)
if doc.jwks_uri:
jwks_uri_str = str(doc.jwks_uri)
try:
await validate_url(jwks_uri_str)
except SSRFError as e:
raise CIMDValidationError(
f"CIMD jwks_uri failed SSRF validation: {e}"
) from e
logger.info(
"CIMD document fetched and validated: %s (client_name=%s)",
client_id_url,
doc.client_name,
)
if not policy.no_store:
self._store_cache_entry(
client_id_url,
_CIMDCacheEntry(
doc=doc,
etag=policy.etag,
last_modified=policy.last_modified,
expires_at=policy.expires_at,
freshness_lifetime=policy.freshness_lifetime,View on GitHub (pinned to 1f02114297)
Solutions
- Host the JWKS at a public HTTPS URL and update jwks_uri in the CIMD document
- Use inline 'jwks' (a JWK Set object) in the document instead of jwks_uri if the keys are small
- If legitimately internal, configure the SSRF allowlist in fastmcp.server.auth.ssrf to permit that endpoint
- Treat repeated occurrences as an attack signal; the validation exists to block SSRF via client-supplied URLs
Example fix
// before "jwks_uri": "http://localhost:8080/jwks.json" // after "jwks_uri": "https://keys.app.example.com/jwks.json"
Defensive patterns
Strategy: validation
Validate before calling
from urllib.parse import urlparse
def jwks_uri_safe(u: str) -> bool:
p = urlparse(u)
host = p.hostname or ""
return p.scheme == "https" and not (
host in ("localhost", "127.0.0.1", "169.254.169.254")
or host.startswith("10.") or host.startswith("192.168.")
or host.startswith("172.16.")
) Try / catch
try:
doc = await fetcher.get_client(client_id)
except CIMDValidationError as e:
if "jwks_uri failed SSRF" in str(e):
raise InvalidClientError("jwks_uri must be a public HTTPS URL") from e
raise Prevention
- Host JWKS on public HTTPS endpoints
- Prefer inline 'jwks' for small key sets to avoid an extra fetch surface
- Never point jwks_uri at internal/metadata services
When it happens
Trigger: A fetched CIMD document contains jwks_uri pointing at localhost, 127.0.0.1, RFC1918 addresses, metadata services (169.254.169.254), or a non-HTTP scheme; detected during fetch/get_client.
Common situations: Malicious or misconfigured client documents attempting SSRF via jwks_uri; internally-hosted JWKS endpoints that worked in dev but are blocked in production; documents authored before SSRF protections were added.
Related errors
- {str(e) from SSRFError/SSRFFetchError}
- JWKS document contains no keys
- Invalid client assertion: {e}
- CIMD redirect_uri must have a host: {uri!r}
- str(e)
AI-assisted analysis of PrefectHQ/fastmcp@1f02114297 (2026-08-29).
Data as JSON: /api/errors/3ea034713ae9216d.
Report an issue: GitHub.