VYPR
Low severity2.7GHSA Advisory· Published Mar 11, 2026· Updated May 7, 2026

CVE-2026-3911

CVE-2026-3911

Description

A flaw was found in Keycloak. An authenticated user with the view-users role could exploit a vulnerability in the UserResource component. By accessing a specific administrative endpoint, this user could improperly retrieve user attributes that were configured to be hidden. This unauthorized information disclosure could expose sensitive user data.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
org.keycloak:keycloak-servicesMaven
<= 26.5.5

Affected products

1

Patches

1
215bc1e27230

Do not return managed attribute as unmanaged if admin has no view permission

https://github.com/keycloak/keycloakPedro IgorMar 11, 2026via ghsa
3 files changed · +51 10
  • services/src/main/java/org/keycloak/services/resources/admin/UserResource.java+1 10 modified
    @@ -1252,18 +1252,9 @@ public void joinGroup(@PathParam("groupId") String groupId) {
         public Map<String, List<String>> getUnmanagedAttributes() {
             auth.users().requireView(user);
             UserProfileProvider provider = session.getProvider(UserProfileProvider.class);
    -
             UserProfile profile = provider.create(USER_API, user);
    -        Map<String, List<String>> managedAttributes = profile.getAttributes().getReadable();
    -        Map<String, List<String>> unmanagedAttributes = profile.getAttributes().getUnmanagedAttributes();
    -        managedAttributes.entrySet().removeAll(unmanagedAttributes.entrySet());
    -        Map<String, List<String>> attributes = new HashMap<>(user.getAttributes());
    -        attributes.entrySet().removeAll(managedAttributes.entrySet());
    -
    -        attributes.remove(UserModel.USERNAME);
    -        attributes.remove(UserModel.EMAIL);
     
    -        return attributes.entrySet().stream()
    +        return profile.getAttributes().getUnmanagedAttributes().entrySet().stream()
                     .filter(entry -> ofNullable(entry.getValue()).orElse(emptyList()).stream().anyMatch(StringUtil::isNotBlank))
                     .collect(Collectors.toMap(Entry::getKey, Entry::getValue));
         }
    
  • tests/base/src/test/java/org/keycloak/tests/admin/user/UserProfileTest.java+45 0 modified
    @@ -18,8 +18,11 @@
     package org.keycloak.tests.admin.user;
     
     import java.util.List;
    +import java.util.Map;
     import java.util.Set;
     
    +import jakarta.ws.rs.core.Response;
    +
     import org.keycloak.admin.client.resource.UserProfileResource;
     import org.keycloak.admin.client.resource.UsersResource;
     import org.keycloak.models.UserModel;
    @@ -29,11 +32,13 @@
     import org.keycloak.representations.idm.UserRepresentation;
     import org.keycloak.representations.userprofile.config.UPAttributePermissions;
     import org.keycloak.representations.userprofile.config.UPConfig;
    +import org.keycloak.representations.userprofile.config.UPConfig.UnmanagedAttributePolicy;
     import org.keycloak.testframework.annotations.InjectRealm;
     import org.keycloak.testframework.annotations.KeycloakIntegrationTest;
     import org.keycloak.testframework.injection.LifeCycle;
     import org.keycloak.testframework.realm.ManagedRealm;
     import org.keycloak.testframework.realm.UserConfigBuilder;
    +import org.keycloak.testframework.util.ApiUtil;
     
     import org.hamcrest.Matchers;
     import org.junit.jupiter.api.Test;
    @@ -176,4 +181,44 @@ public void defaultMaxResultsBrief() {
                 upResource.update(upConfig);
             }
         }
    +
    +    @Test
    +    public void testGetUnmanagedAttributes() {
    +        UserProfileResource upResource = managedRealm.admin().users().userProfile();
    +        UPConfig upConfig = upResource.getConfiguration();
    +        upConfig.addOrReplaceAttribute(createAttributeMetadata("aName"));
    +        upResource.update(upConfig);
    +
    +        try {
    +            UsersResource users = managedRealm.admin().users();
    +            UserRepresentation user = UserConfigBuilder.create().username("test-user").attribute("aName", "aValue").build();
    +            try (Response response = users.create(user)) {
    +                user.setId(ApiUtil.getCreatedId(response));
    +            }
    +            Map<String, List<String>> unmanagedAttributes = users.get(user.getId()).getUnmanagedAttributes();
    +            assertTrue(unmanagedAttributes.isEmpty());
    +
    +            upConfig.setUnmanagedAttributePolicy(UnmanagedAttributePolicy.ENABLED);
    +            upResource.update(upConfig);
    +            user.getAttributes().put("unmanaged", List.of("value"));
    +            users.get(user.getId()).update(user);
    +            unmanagedAttributes = users.get(user.getId()).getUnmanagedAttributes();
    +            assertThat(unmanagedAttributes.keySet(), hasSize(1));
    +            upConfig.removeAttribute("aName");
    +            upResource.update(upConfig);
    +            unmanagedAttributes = users.get(user.getId()).getUnmanagedAttributes();
    +            assertThat(unmanagedAttributes.keySet(), hasSize(2));
    +            upConfig.addOrReplaceAttribute(createAttributeMetadata("aName"));
    +            upResource.update(upConfig);
    +            unmanagedAttributes = users.get(user.getId()).getUnmanagedAttributes();
    +            assertThat(unmanagedAttributes.keySet(), hasSize(1));
    +            upConfig.getAttribute("aName").setPermissions(new UPAttributePermissions(Set.of("user"), Set.of("user")));
    +            upResource.update(upConfig);
    +            unmanagedAttributes = users.get(user.getId()).getUnmanagedAttributes();
    +            assertThat(unmanagedAttributes.keySet(), hasSize(1));
    +        } finally {
    +            upConfig.removeAttribute("aName");
    +            upResource.update(upConfig);
    +        }
    +    }
     }
    
  • tests/base/src/test/java/org/keycloak/tests/workflow/WorkflowScheduleTest.java+5 0 modified
    @@ -6,6 +6,8 @@
     
     import org.keycloak.admin.client.resource.UserResource;
     import org.keycloak.models.workflow.SetUserAttributeStepProviderFactory;
    +import org.keycloak.representations.userprofile.config.UPConfig;
    +import org.keycloak.representations.userprofile.config.UPConfig.UnmanagedAttributePolicy;
     import org.keycloak.representations.workflows.WorkflowRepresentation;
     import org.keycloak.representations.workflows.WorkflowScheduleRepresentation;
     import org.keycloak.representations.workflows.WorkflowStepRepresentation;
    @@ -32,6 +34,9 @@ public class WorkflowScheduleTest extends AbstractWorkflowTest {
     
         @Test
         public void testSchedule() {
    +        UPConfig upConfig = managedRealm.admin().users().userProfile().getConfiguration();
    +        upConfig.setUnmanagedAttributePolicy(UnmanagedAttributePolicy.ADMIN_VIEW);
    +        managedRealm.admin().users().userProfile().update(upConfig);
             WorkflowRepresentation expectedWorkflow = WorkflowRepresentation.withName("myworkflow")
                     .schedule(WorkflowScheduleRepresentation.create().after("1s").batchSize(10).build())
                     .withSteps(
    

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

9

News mentions

0

No linked articles in our index yet.