Apache ZooKeeper: Insufficient Permission Check in AdminServer Snapshot/Restore Commands
Description
Improper permission check in ZooKeeper AdminServer lets authorized clients to run snapshot and restore command with insufficient permissions.
This issue affects Apache ZooKeeper: from 3.9.0 before 3.9.4.
Users are recommended to upgrade to version 3.9.4, which fixes the issue.
The issue can be mitigated by disabling both commands (via admin.snapshot.enabled and admin.restore.enabled), disabling the whole AdminServer interface (via admin.enableServer), or ensuring that the root ACL does not provide open permissions. (Note that ZooKeeper ACLs are not recursive, so this does not impact operations on child nodes besides notifications from recursive watches.)
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Improper permission check in ZooKeeper AdminServer allows authorized clients to run snapshot/restore commands with insufficient privileges.
Vulnerability
Description CVE-2025-58457 is an improper permission check in Apache ZooKeeper's AdminServer that allows authenticated clients to execute snapshot and restore commands even when they lack the required ADMIN permission. The root cause is that the AdminServer did not properly validate that the user had the necessary ACL permissions for these sensitive operations, relying instead on a less restrictive check [1][3]. A fix addressing this was committed in commit 71e173f, which ensures permissions are individually verified during authentication [4].
Exploitation
An attacker must be an authenticated client of ZooKeeper with at least some level of access (e.g., through a permissive root ACL). The AdminServer interface, if enabled, exposes endpoints for snapshot and restore commands. The attacker can then issue these commands without having the ADMIN permission, effectively bypassing access controls. The attack does not require elevated privileges beyond the initial authentication, and can be performed remotely if the AdminServer network interface is accessible [1][3].
Impact
Successful exploitation allows an attacker to take snapshots of the ZooKeeper data tree, leading to data exfiltration, or to restore snapshots, potentially corrupting the data store or enabling further privilege escalation. This compromises the confidentiality and integrity of the ZooKeeper service, which is critical for distributed coordination [3].
Mitigation
The vulnerability affects ZooKeeper versions 3.9.0 through 3.9.3. Users should upgrade to version 3.9.4, which contains the fix [1][2]. As workarounds, administrators can disable the snapshot and restore commands via the admin.snapshot.enabled and admin.restore.enabled settings, disable the entire AdminServer with admin.enableServer=false, or ensure that the root ACL does not provide open permissions (note that ZooKeeper ACLs are not recursive, so this does not affect child nodes except for recursive watch notifications) [1][3].
AI Insight generated on May 19, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.apache.zookeeper:zookeeperMaven | >= 3.9.0, < 3.9.4 | 3.9.4 |
Affected products
2- Apache Software Foundation/Apache ZooKeeperv5Range: 3.9.0
Patches
171e173fcbcc9ZOOKEEPER-4964. Check permissions individually during admin server auth
3 files changed · +59 −12
zookeeper-server/src/main/java/org/apache/zookeeper/server/admin/Commands.java+20 −1 modified@@ -227,6 +227,18 @@ private static List<Id> handleAuthentication(final HttpServletRequest request, f } } + /** + * Grant or deny authorization for a command by matching + * request-provided credentials with the ACLs present on a node. + * + * @param zkServer the ZooKeeper server object. + * @param ids the credentials extracted from the Authorization header. + * @param perm the set of permission bits required by the command. + * @param path the ZooKeeper node path whose ACLs should be used + * to satisfy the perm bits. + * @throws KeeperException.NoAuthException if one or more perm + * bits could not be satisfied. + */ private static void handleAuthorization(final ZooKeeperServer zkServer, final List<Id> ids, final int perm, @@ -237,7 +249,14 @@ private static void handleAuthorization(final ZooKeeperServer zkServer, throw new KeeperException.NoNodeException(path); } final List<ACL> acls = zkServer.getZKDatabase().aclForNode(dataNode); - zkServer.checkACL(null, acls, perm, ids, path, null); + // Check the individual bits of perm. + final int bitWidth = Integer.SIZE - Integer.numberOfLeadingZeros(perm); + for (int b = 0; b < bitWidth; b++) { + final int permBit = 1 << b; + if ((perm & permBit) != 0) { + zkServer.checkACL(null, acls, permBit, ids, path, null); + } + } } /**
zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/CommandAuthTest.java+37 −9 modified@@ -29,9 +29,11 @@ import java.net.HttpURLConnection; import java.net.URL; import java.nio.charset.StandardCharsets; +import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.List; import java.util.Map; import javax.net.ssl.HttpsURLConnection; import javax.net.ssl.SSLContext; @@ -185,6 +187,22 @@ public void testAuthCheck_noACL(final AuthSchema authSchema) throws Exception { assertEquals(HttpURLConnection.HTTP_OK, authTestConn.getResponseCode()); } + @ParameterizedTest + @EnumSource(value = AuthSchema.class, names = {"DIGEST"}) + public void testAuthCheck_noPerms(final AuthSchema authSchema) throws Exception { + // The extra ACL entry gives Perms.READ perms to the "invalid" + // DIGEST authInfo---but that should not permit access, as + // AuthTestCommand requires Perms.ADMIN. + setupRootACL(authSchema, ZooDefs.Ids.READ_ACL_UNSAFE); + try { + final HttpURLConnection authTestConn = sendAuthTestCommandRequest(authSchema, false); + assertEquals(HttpURLConnection.HTTP_FORBIDDEN, authTestConn.getResponseCode()); + } finally { + addAuthInfo(zk, authSchema); + resetRootACL(zk); + } + } + @Test public void testAuthCheck_invalidServerRequiredConfig() { assertThrows("An active server is required for auth check", @@ -300,19 +318,29 @@ public void clearTLS() { } private void setupRootACL(final AuthSchema authSchema) throws Exception { + setupRootACL(authSchema, Collections.<ACL>emptyList()); + } + + private void setupRootACL(final AuthSchema authSchema, final List<ACL> extraEntries) throws Exception { + final List<ACL> aclEntries = new ArrayList<>(); + switch (authSchema) { case DIGEST: - setupRootACLForDigest(zk); + aclEntries.addAll(genACLForDigest()); break; case X509: - setupRootACLForX509(zk); + aclEntries.addAll(genACLForX509()); break; case IP: - setupRootACLForIP(zk); + aclEntries.addAll(genACLForIP()); break; default: throw new IllegalArgumentException("Unknown auth schema"); } + + aclEntries.addAll(extraEntries); + + zk.setACL(Commands.ROOT_PATH, aclEntries, -1); } private HttpURLConnection sendAuthTestCommandRequest(final AuthSchema authSchema, final boolean validAuthInfo) throws Exception { @@ -343,22 +371,22 @@ public static void resetRootACL(final ZooKeeper zk) throws Exception { zk.setACL(Commands.ROOT_PATH, OPEN_ACL_UNSAFE, -1); } - public static void setupRootACLForDigest(final ZooKeeper zk) throws Exception { + public static List<ACL> genACLForDigest() throws Exception { final String idPassword = String.format("%s:%s", ROOT_USER, ROOT_PASSWORD); final String digest = DigestAuthenticationProvider.generateDigest(idPassword); final ACL acl = new ACL(ZooDefs.Perms.ALL, new Id(DIGEST_SCHEMA, digest)); - zk.setACL(Commands.ROOT_PATH, Collections.singletonList(acl), -1); + return Collections.singletonList(acl); } - private static void setupRootACLForX509(final ZooKeeper zk) throws Exception { + private static List<ACL> genACLForX509() throws Exception { final ACL acl = new ACL(ZooDefs.Perms.ALL, new Id(X509_SCHEMA, X509_SUBJECT_PRINCIPAL)); - zk.setACL(Commands.ROOT_PATH, Collections.singletonList(acl), -1); + return Collections.singletonList(acl); } - private static void setupRootACLForIP(final ZooKeeper zk) throws Exception { + private static List<ACL> genACLForIP() throws Exception { final ACL acl = new ACL(ZooDefs.Perms.ALL, new Id(IP_SCHEMA, "127.0.0.1")); - zk.setACL(Commands.ROOT_PATH, Collections.singletonList(acl), -1); + return Collections.singletonList(acl); } public static void addAuthInfoForDigest(final ZooKeeper zk) {
zookeeper-server/src/test/java/org/apache/zookeeper/server/admin/SnapshotAndRestoreCommandTest.java+2 −2 modified@@ -21,7 +21,7 @@ import static org.apache.zookeeper.server.ZooKeeperServer.ZOOKEEPER_SERIALIZE_LAST_PROCESSED_ZXID_ENABLED; import static org.apache.zookeeper.server.admin.CommandAuthTest.addAuthInfoForDigest; import static org.apache.zookeeper.server.admin.CommandAuthTest.resetRootACL; -import static org.apache.zookeeper.server.admin.CommandAuthTest.setupRootACLForDigest; +import static org.apache.zookeeper.server.admin.CommandAuthTest.genACLForDigest; import static org.apache.zookeeper.server.admin.Commands.ADMIN_RATE_LIMITER_INTERVAL; import static org.apache.zookeeper.server.admin.Commands.RestoreCommand.ADMIN_RESTORE_ENABLED; import static org.apache.zookeeper.server.admin.Commands.SnapshotCommand.ADMIN_SNAPSHOT_ENABLED; @@ -119,7 +119,7 @@ public void setup() throws Exception { zk = ClientBase.createZKClient(hostPort); // setup root ACL - setupRootACLForDigest(zk); + zk.setACL(Commands.ROOT_PATH, genACLForDigest(), -1); // add auth addAuthInfoForDigest(zk);
Vulnerability mechanics
Generated 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-2hmj-97jw-28jhghsaADVISORY
- lists.apache.org/thread/r5yol0kkhx2fzw22pxk1ozwm3oc6yxrxghsavendor-advisoryWEB
- nvd.nist.gov/vuln/detail/CVE-2025-58457ghsaADVISORY
- github.com/apache/zookeeper/commit/71e173fcbcc9deb784081cf867bd045df3c32635ghsaWEB
- www.openwall.com/lists/oss-security/2025/09/24/10ghsaWEB
- zookeeper.apache.org/doc/current/zookeeperSnapshotAndRestore.htmlghsaWEB
- zookeeper.apache.org/doc/r3.9.4/releasenotes.htmlghsaWEB
- zookeeper.apache.org/security.htmlghsaWEB
News mentions
0No linked articles in our index yet.