VYPR
High severity8.1NVD Advisory· Published Apr 2, 2026· Updated Apr 16, 2026

CVE-2026-4636

CVE-2026-4636

Description

A flaw was found in Keycloak. An authenticated user with the uma_protection role can bypass User-Managed Access (UMA) policy validation. This allows the attacker to include resource identifiers owned by other users in a policy creation request, even if the URL path specifies an attacker-owned resource. Consequently, the attacker gains unauthorized permissions to victim-owned resources, enabling them to obtain a Requesting Party Token (RPT) and access sensitive information or perform unauthorized actions.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.keycloak:keycloak-servicesMaven
< 26.5.726.5.7

Affected products

5
  • cpe:2.3:a:redhat:build_of_keycloak:26.2.15:*:*:*:text-only:*:*:*+ 4 more
    • cpe:2.3:a:redhat:build_of_keycloak:26.2.15:*:*:*:text-only:*:*:*
    • cpe:2.3:a:redhat:build_of_keycloak:26.2:*:*:*:text-only:*:*:*
    • cpe:2.3:a:redhat:build_of_keycloak:26.4.11:*:*:*:text-only:*:*:*
    • cpe:2.3:a:redhat:build_of_keycloak:26.4:*:*:*:text-only:*:*:*
    • cpe:2.3:a:redhat:build_of_keycloak:-:*:*:*:text-only:*:*:*

Patches

1
995832f8b74b

Prevent creating policies if they don't reference only the owner resource (#496)

https://github.com/keycloak/keycloakPedro IgorMar 26, 2026via ghsa
2 files changed · +37 0
  • services/src/main/java/org/keycloak/authorization/protection/policy/UserManagedPermissionService.java+6 0 modified
    @@ -178,6 +178,12 @@ private void checkRequest(String resourceId, UmaPermissionRepresentation represe
                 if (!resourceScopes.containsAll(scopes)) {
                     throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Some of the scopes [" + scopes + "] are not valid for resource [" + resourceId + "]", Response.Status.BAD_REQUEST);
                 }
    +
    +            Set<String> resources = Optional.ofNullable(representation.getResources()).orElse(Set.of());
    +
    +            if (!resources.isEmpty() && (resources.size() != 1 || !resources.contains(resource.getId()))) {
    +                throw new ErrorResponseException(OAuthErrorException.INVALID_REQUEST, "Invalid resource", Response.Status.BAD_REQUEST);
    +            }
             }
         }
     
    
  • testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/authz/UserManagedPermissionServiceTest.java+31 0 modified
    @@ -23,6 +23,7 @@
     import java.util.UUID;
     
     import jakarta.ws.rs.NotFoundException;
    +import jakarta.ws.rs.core.Response.Status;
     
     import org.keycloak.admin.client.resource.UsersResource;
     import org.keycloak.authorization.client.AuthorizationDeniedException;
    @@ -128,6 +129,36 @@ private void testCreate() {
     
             ProtectionResource protection = getAuthzClient().protection("marta", "password");
     
    +        ResourceRepresentation resourceB = new ResourceRepresentation();
    +
    +        resourceB.setName("Resource B");
    +        resourceB.setOwnerManagedAccess(true);
    +        resourceB.setOwner("kolo");
    +        resourceB.addScope("Scope A", "Scope B", "Scope C");
    +        resourceB = getAuthzClient().protection().resource().create(resourceB);
    +        newPermission.addResource(resourceB.getId());
    +
    +        try {
    +            protection.policy(resource.getId()).create(newPermission);
    +            fail("Should fail, not allowed to set a resource other than the one referenced in the path");
    +        } catch (RuntimeException ignore) {
    +            Throwable cause = ignore.getCause();
    +            assertTrue(cause instanceof HttpResponseException);
    +            assertEquals(Status.BAD_REQUEST.getStatusCode(), ((HttpResponseException) cause).getStatusCode());
    +        }
    +
    +        try {
    +            newPermission.addResource(resource.getId());
    +            protection.policy(resource.getId()).create(newPermission);
    +            fail("Should fail, not allowed to set a resource other than the one referenced in the path");
    +        } catch (RuntimeException ignore) {
    +            Throwable cause = ignore.getCause();
    +            assertTrue(cause instanceof HttpResponseException);
    +            assertEquals(Status.BAD_REQUEST.getStatusCode(), ((HttpResponseException) cause).getStatusCode());
    +        }
    +
    +        newPermission.getResources().remove(resourceB.getId());
    +
             UmaPermissionRepresentation permission = protection.policy(resource.getId()).create(newPermission);
     
             assertEquals(newPermission.getName(), permission.getName());
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

10

News mentions

0

No linked articles in our index yet.