Low severity3.8NVD Advisory· Published Feb 19, 2026· Updated Apr 15, 2026
CVE-2026-2733
CVE-2026-2733
Description
A flaw was identified in the Docker v2 authentication endpoint of Keycloak, where tokens continue to be issued even after a Docker registry client has been administratively disabled. This means that turning the client “Enabled” setting to OFF does not fully prevent access. As a result, previously valid credentials can still be used to obtain authentication tokens. This weakens administrative controls and could allow unintended access to container registry resources.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.keycloak:keycloak-servicesMaven | <= 26.5.3 | — |
Patches
1743ac24081b2Check client is enabled in the docker endpoint
2 files changed · +43 −9
services/src/main/java/org/keycloak/protocol/docker/DockerEndpoint.java+22 −9 modified@@ -5,6 +5,7 @@ import jakarta.ws.rs.core.Response; import org.keycloak.common.Profile; +import org.keycloak.events.Errors; import org.keycloak.events.EventBuilder; import org.keycloak.events.EventType; import org.keycloak.models.AuthenticationFlowModel; @@ -40,6 +41,7 @@ public class DockerEndpoint extends AuthorizationEndpointBase { public DockerEndpoint(KeycloakSession session, final EventBuilder event, final EventType login) { super(session, event); this.login = login; + event.event(login); } @GET @@ -54,19 +56,11 @@ public Response build() { "username is provided by Basic auth header."); } service = params.getFirst(DockerAuthV2Protocol.SERVICE_PARAM); - if (service == null) { - throw new ErrorResponseException("invalid_request", "service parameter must be provided", Response.Status.BAD_REQUEST); - } - client = realm.getClientByClientId(service); - if (client == null) { - logger.errorv("Failed to lookup client given by service={0} parameter for realm: {1}.", service, realm.getName()); - throw new ErrorResponseException("invalid_client", "Client specified by 'service' parameter does not exist", Response.Status.BAD_REQUEST); - } - session.getContext().setClient(client); scope = params.getFirst(DockerAuthV2Protocol.SCOPE_PARAM); checkSsl(); checkRealm(); + checkService(); final AuthorizationEndpointRequest authRequest = AuthorizationEndpointRequestParserProcessor.parseRequest(event, session, client, params, AuthorizationEndpointRequestParserProcessor.EndpointType.DOCKER_ENDPOINT); authenticationSession = createAuthenticationSession(client, authRequest.getState()); @@ -94,6 +88,25 @@ private void updateAuthenticationSession() { } + private void checkService() { + if (service == null) { + event.error(Errors.INVALID_REQUEST); + throw new ErrorResponseException("invalid_request", "service parameter must be provided", Response.Status.BAD_REQUEST); + } + client = realm.getClientByClientId(service); + if (client == null) { + event.error(Errors.CLIENT_NOT_FOUND); + logger.errorv("Failed to lookup client given by service={0} parameter for realm: {1}.", service, realm.getName()); + throw new ErrorResponseException("invalid_client", "Client specified by 'service' parameter does not exist", Response.Status.BAD_REQUEST); + } + if (!client.isEnabled()) { + event.error(Errors.CLIENT_DISABLED); + logger.errorv("The service {0} in realm {1} is disabled.", service, realm.getName()); + throw new ErrorResponseException("invalid_client", "Client specified by 'service' is disabled", Response.Status.BAD_REQUEST); + } + session.getContext().setClient(client); + } + @Override protected AuthenticationFlowModel getAuthenticationFlow(AuthenticationSessionModel authSession) { return realm.getDockerAuthenticationFlow();
testsuite/integration-arquillian/tests/base/src/test/java/org/keycloak/testsuite/docker/DockerClientTest.java+21 −0 modified@@ -8,13 +8,16 @@ import java.util.Map; import java.util.Optional; +import org.keycloak.admin.client.resource.ClientResource; import org.keycloak.common.Profile; import org.keycloak.common.util.PemUtils; import org.keycloak.crypto.KeyStatus; import org.keycloak.models.Constants; +import org.keycloak.representations.idm.ClientRepresentation; import org.keycloak.representations.idm.KeysMetadataRepresentation; import org.keycloak.representations.idm.RealmRepresentation; import org.keycloak.testsuite.AbstractKeycloakTest; +import org.keycloak.testsuite.admin.ApiUtil; import org.keycloak.testsuite.arquillian.annotation.EnableFeature; import org.junit.Assert; @@ -31,7 +34,9 @@ import static org.keycloak.testsuite.util.WaitUtils.pause; import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.containsString; import static org.hamcrest.Matchers.is; +import static org.hamcrest.Matchers.not; import static org.junit.Assume.assumeTrue; @EnableFeature(Profile.Feature.DOCKER) @@ -162,6 +167,22 @@ public void shouldPerformDockerAuthAgainstRegistry() throws Exception { result = dockerClientContainer.execInContainer("docker", "push", REGISTRY_HOSTNAME + ":" + REGISTRY_PORT + "/empty"); printCommandResult(result); assertThat("Error pushing to registry", result.getExitCode(), is(0)); + + // logout + result = dockerClientContainer.execInContainer("docker", "logout"); + printCommandResult(result); + assertThat("Error performing logout", result.getExitCode(), is(0)); + + // disable and login should fail + ClientResource client = ApiUtil.findClientByClientId(adminClient.realm(REALM_ID), CLIENT_ID); + ClientRepresentation clientRep = client.toRepresentation(); + clientRep.setEnabled(Boolean.FALSE); + client.update(clientRep); + + result = dockerClientContainer.execInContainer("docker", "login", "-u", DOCKER_USER, "-p", DOCKER_USER_PASSWORD, REGISTRY_HOSTNAME + ":" + REGISTRY_PORT); + printCommandResult(result); + assertThat("Error performing login", result.getExitCode(), not(is(0))); + assertThat("Service is not disabled", result.getStderr(), containsString("Client specified by 'service' is disabled")); } private void printCommandResult(Container.ExecResult result) {
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
8- github.com/advisories/GHSA-fjf4-6f34-w64qghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2026-2733ghsaADVISORY
- access.redhat.com/errata/RHSA-2026:3947nvdWEB
- access.redhat.com/errata/RHSA-2026:3948nvdWEB
- access.redhat.com/security/cve/CVE-2026-2733nvdWEB
- bugzilla.redhat.com/show_bug.cginvdWEB
- github.com/keycloak/keycloak/commit/743ac24081b2c6da36aac3775147ec5b80c2861eghsaWEB
- github.com/keycloak/keycloak/issues/46462ghsaWEB
News mentions
0No linked articles in our index yet.