ZooKeeper's client port is not a metric for exposed quorums
ZooKeeper's client port is not a metric for exposed quorums A scan for port=2181 returns 2,432,899 matches on ZoomEye. A query for the ZooKeeper fingerprint, app="Apache ZooKeeper", returns 93,303. The two numbers diff
ZooKeeper's client port is not a metric for exposed quorums
A scan for port=2181 returns 2,432,899 matches on ZoomEye. A query for the ZooKeeper fingerprint, app="Apache ZooKeeper", returns 93,303. The two numbers differ by a factor of twenty-six, and the gap is the most useful thing an operator can take from either.
Both figures were collected on 23 October 2026 through the ZoomEye API, one result per query, using the totals the service reports. They answer different questions. The port query counts hosts that answer on 2181, whatever is listening. The application query counts hosts whose banner or service response matches ZoomEye's ZooKeeper fingerprint.
The distinction matters this month because Apache published four ZooKeeper security advisories on 16 September 2026, two of which concern access control on the client protocol. Any inventory built from a port scan will be wrong about the size of that population, and the direction of the error is not predictable.
What the advisories changed
CVE-2026-79993 describes the deleteContainer opcode, value 20, being processed without verifying the caller's ACL permissions. Apache's advisory says a client that can open a plain TCP session on the client port can delete an empty persistent znode regardless of the ACLs on that node or its parent, and that the request path skips both the session check and the DELETE ACL check that the regular delete path enforces. It affects 3.9.0 to 3.9.5 and 3.8.0 to 3.8.6.
CVE-2026-59739 describes an incomplete fix for CVE-2024-23944. ACL checking was added to WatchManager.triggerWatch(), while DataTree.setWatches(), which replays watch registrations on reconnect, still delivers events with a null ACL. The advisory limits the disclosure to node paths rather than node data and notes that paths can contain usernames or login identifiers.
Both are fixed in 3.9.6 and 3.8.7. Neither requires credentials to reach the vulnerable code path in the adversarial model the advisories describe.
Reading the fingerprint numbers honestly
The app="Apache ZooKeeper" total of 93,303 is a measurement of identifiable deployments, not a count of vulnerable ones. ZoomEye's fingerprinting depends on what the service emits and which probes succeed. A deployment that restricts the four-letter-word commands, front-ends 2181 with a network policy, or runs an older release whose banner is less distinctive may be absent from that total while remaining present in a port count.
The geographic split is instructive rather than predictive. The same fingerprint restricted with country="CN" returns 2,372 matches; with country="US" it returns 1,435. These are counts of matching hosts in public scan data, and they say nothing about which organisation operates them or whether any of them is unpatched.
A TLS view is narrower still. app="Apache ZooKeeper" && service="ssl" returns 223 matches, a small minority of the identified population. Encrypting the client port does not by itself address an ACL bypass, and the count should not be read as a security posture indicator. It is useful for a different question: how much of the identified population terminates TLS on the client port at all.
Quorum traffic tells a fourth story. Ports 2888 and 3888, used for quorum communication and leader election, return 5 and 1 matches respectively. Those numbers are not a measurement of quorum exposure, because quorum traffic in a healthy ensemble does not answer an unauthenticated probe in a fingerprintable way. They are a reminder that a public scan sees what responds, and silence is not evidence of isolation.
Turning counts into a coverage decision
The operational task after these advisories is not estimating how many ZooKeepers exist on the internet. It is establishing whether your own inventory includes the ones you run.
Start from the side you control. Configuration management, container registries and package inventories name the version of every zookeeper package deployed; those records are more reliable than any external count and can be reconciled with the two fixes in 3.9.6 and 3.8.7. An ensemble pinned to 3.9.4 will appear in neither the 93,303 nor the 2,432,899 total if it is correctly segmented, and it is still affected.
Then use external measurement for the question it answers well: whether anything you did not know about is reachable. A query restricted to your own ASN, certificate organisation or netblock, for the ZooKeeper fingerprint and for port 2181, produces a short list that can be compared against inventory. If it contains a host that nobody expected, that is a finding independent of the CVE.
The reverse comparison is where teams go wrong. Treating an empty result for your netblock as evidence that remediation is complete assumes the scanner sees what you see. A deployment where the four-letter-word interface is whitelisted and no application fingerprint is emitted can serve clients on 2181 for years without appearing in an application query.
Specific checks worth running
Version confirmation is quick where srvr is enabled: echo srvr | nc <host> 2181 returns a Zookeeper version line. Restricting zookeeper.4lw.commands.whitelist to the commands you need is separate hardening, and narrowing it may remove srvr from your own diagnostic toolkit.
For the ACL bypass, a regression test against a protected leaf node is more informative than a scan. Create an empty node with a restrictive ACL on a test ensemble, attempt a container delete from a raw protocol client, and record whether the server refuses. Repeat after the upgrade.
Watch configuration management for the version string, not the container tag. Upstream images are rebuilt on base-image changes, and a tag that reads 3.9 tells you nothing about whether the running binary is 3.9.5 or 3.9.6.
References
- Apache ZooKeeper advisory for CVE-2026-79993: https://lists.apache.org/thread/9cw3rmrzhqpct26v8j18fy41bghlq8y5
- Apache ZooKeeper advisory for CVE-2026-59739: https://lists.apache.org/thread/v0lrwsbdxvx6w67p3z7fxf3hzyncq55l
- Openwall mirrors: http://www.openwall.com/lists/oss-security/2026/09/15/5, http://www.openwall.com/lists/oss-security/2026/09/15/7
- ZoomEye query syntax reference: https://www.zoomeye.org/doc
- NVD records: https://nvd.nist.gov/vuln/detail/CVE-2026-79993, https://nvd.nist.gov/vuln/detail/CVE-2026-59739
- Measurement note: counts collected 23 October 2026 with
app="Apache ZooKeeper"(93,303),port=2181(2,432,899),app="Apache ZooKeeper" && country="CN"(2,372),app="Apache ZooKeeper" && country="US"(1,435),app="Apache ZooKeeper" && service="ssl"(223),port=2888(5),port=3888(1).
Originally published by Dev.to Security. Aggregated on AIWithGhost for educational purposes — full credit and traffic to the original publisher.