8000 [CVE-2026-37977] CORS Access-Control-Allow-Origin reflected from unverified JWT azp claim on UMA token endpoint · Issue #48036 · keycloak/keycloak · GitHub
[go: up one dir, main page]

Skip to content
8000

[CVE-2026-37977] CORS Access-Control-Allow-Origin reflected from unverified JWT azp claim on UMA token endpoint #48036

Closed

Description

@ahus1

Description

CVE-2026-37977: When using the UMA token endpoint, Keycloak sets the Access-Control-Allow-Origin response header based on the azp claim from a client-provided JWT before validating the JWT signature. While the token grant itself is correctly rejected during validation, the CORS header has already been set in the response.

This allows a client to control which origin can read the error response cross-origin. The impact is limited to reading error messages - no tokens or user data are exposed.

Prerequisites:

  • Client must be configured with webOrigins: ["*"] (non-default configuration)
  • Only affects error responses, not successful token grants

Version Affected

26.5.6 and potentially other versions

Steps to Reproduce

  1. Configure a Keycloak client with webOrigins: ["*"]
  2. Create a JWT with the azp claim set to any origin (e.g., https://example.com)
  3. Sign the JWT with any key (signature validation will fail later)
  4. Send a POST request to /realms/{realm}/protocol/openid-connect/token with:
    • grant_type=urn:ietf:params:oauth:grant-type:uma-ticket
    • Include the crafted JWT
  5. Inspect the response headers

Expected Behavior

The Access-Control-Allow-Origin header should only be set after JWT signature validation, or should be based on the client's configured origins rather than the unverified azp claim.

Actual Behavior

The Access-Control-Allow-Origin header reflects the value from the azp claim before signature verification, allowing the error response to be read cross-origin from any specified domain.

Additional Context

This issue has been assigned CVE-2026-37977 for tracking purposes.

The practical impact is limited because:

  • Only error responses are affected
  • No tokens or user data are exposed
  • Requires non-default client configuration
  • The token grant itself is correctly rejected

This issue was originally tracked in the private repository. Migrated by @ahus1.

Activity

  1. added
    area/authorization-servicesAuthorization Services — UMA, policies, permissions, resource servers
    kind/cveIssues identified as CVEs on third-party dependencies, or issues which Keycloak is not affected
    on Apr 14, 2026
  2. added theissue type on Apr 14, 2026
  3. ahus1 commented on Apr 14, 2026

    @ahus1
    MemberAuthor

    @pedroigor - please schedule this in your team.

    I've assigned you to this issue for the time being to do additional labeling and planning.

  4. pedroigor commented on Apr 15, 2026

    @pedroigor
    Contributor

    Resuming from:

    > pedroigor:
    The only thing I'm not sure about this one is that the client making the request can be a SPA and, as such, it does not have any CORS setup. It is not the backend.
    
    In such a scenario, the public client is obtaining permissions from another client (the audience, the resource server) to access its protected resources. In this case, shouldn't the token endpoint return the CORS requirements from the resource server? Wouldn't it be a way to allow a resource server to enforce specific requirements for cross-origin requests, including which clients/domains are allowed? If so, the behavior herein described is valid.
    
    However, I also understand the point from the reporter. You might want to expose only the CORS requirements for the client (e.g.: SPA) making the request. Perhaps suggesting allowing management of CORS configuration from a client/resource server?
    
    > stianst:
    Actually, the way CORS works for other endpoints is that the RP gets the permitted web-origins in the access token, and it's configured in the app, not the backend service. Our adapters just used to take the web-origin claim from the access token.
    
  5. ValeriaEpifanova commented on Apr 28, 2026

    @ValeriaEpifanova
    Contributor

    @ahus1 @pedroigor Hello everyone! According to steps of reproducing if we open PermissionGrantType class we can see that CORS sets before throwing the CorsErrorResponseException. In case when token is invalid.
    The question is should we set CORS only when client "web origins" claim doesn't contain "*"?

    For example something like

    Set clientOrigin = WebOriginsUtils.resolveValidWebOrigins(session, client);
    if (!clientOrigin.contains("*")) {
    cors.allowedOrigins(session, client);
    }

  6. pedroigor commented on May 27, 2026

    @pedroigor
    Contributor

    @ValeriaEpifanova From the last comment from @stianst, we should resolve the allowed origins from the bearer token because tokens issued by Keycloak will have a specific claim with the web origins.

  7. pedroigor commented on May 29, 2026

    @pedroigor
    Contributor
  8. 6 remaining items

  9. added a commit that references this issue on Jun 8, 2026
    1439bd5
  10. added a commit that references this issue on Jun 24, 2026
    931919f
  11. added a commit that references this issue on Jul 20, 2026
    ae2924c
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Type

Fields

No fields configured for cve.

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions

    0