Produced with the
threat-model-producerskill (https://gist.github.com/potiuk/da14a826283038ddfe38cc9fe6310573). This is the implicit contract between ZooKeeper and its downstream operators/integrators: what is in scope, what is out, what the project claims, and what it disclaims. It is not an audit, a CVE list, or a secure-coding guide.
- Project: Apache ZooKeeper (server + Java client + Jute serialization).
- Version / commit:
3.10.0-SNAPSHOT, commit9b535738d(branchfix/4820_change_logback_scope). - Date: 2026-06-18.
- Author(s): Draft generated for maintainer review. Not yet ratified.
- Status: DRAFT — not yet reviewed by the ZooKeeper PMC. Heavily
(inferred); treat §8/§9 boundaries as proposals until confirmed. - Version binding: A report against ZooKeeper version N is triaged against this model as it stood at N, not at HEAD. Defaults change between minor releases (e.g.
fips-modeflipped default between 3.8.x and 3.9.0); always read the row for the reported version. - Reporting cross-reference: Findings that violate a §8 claimed property should be reported privately to
security@zookeeper.apache.orgper https://zookeeper.apache.org/security.html (documented). Findings that fall under §3 (out of scope) or §9 (disclaimed) will be closed citing this document. - Provenance legend:
- (documented) — stated in ZooKeeper's own docs (Admin/Programmer guides, Reconfig guide, security page) or directly in code. Cited.
- (maintainer) — stated by a maintainer in response to this process. None yet (draft-first).
- (inferred) — reasoned from code structure or domain knowledge; has a matching §14 open question.
- Draft confidence: ~58 documented / 0 maintainer / ~22 inferred. This is a public-artifact draft; the
(inferred)claims in §3, §5, §7, §9 are the priority confirmation targets. - What ZooKeeper is: A distributed coordination service. A small ensemble of servers (typically 3/5/7) replicates a hierarchical key/value namespace (the "data tree" of znodes) using the ZAB atomic-broadcast protocol, and serves reads, writes, watches, and ephemeral/sequential nodes to many client applications. It is the coordination backbone for systems like Kafka, HBase, and Solr — used for leader election, configuration, locks, and membership. It is a stateful network service, not an in-process library.
-
Primary intended use: An in-datacenter, operator-deployed coordination ensemble accessed by trusted application processes over a low-latency network. Concrete uses: configuration storage, distributed locks, leader election, group membership, service discovery.
-
Deployment context: Long-running server (
QuorumPeerMain/ZooKeeperServerMain) plus an embedded Java client library. (documented: zookeeperAdmin.md, zookeeperOver.md) -
Caller roles (a network service has no single "caller"):
- Client application — connects on the client port, holds sessions, reads/writes znodes. Authenticated only if the operator opts in (see §6/§7). (documented)
- Operator / admin — runs the JVMs, owns
zoo.cfg, JAAS, keystores, super-user credentials, the AdminServer, JMX. Fully trusted for the instance. (documented) - Peer server — another ensemble member participating in ZAB / leader election. Authenticated only if quorum SASL or quorum TLS is enabled (off by default). (documented: QuorumPeerConfig.java)
-
Component-family table:
Family Representative entry point Touches outside process? In model? Server core (data tree, ACL check, ZAB, sessions) client port 2181; ZooKeeperServer,PrepRequestProcessor,DataTreenetwork, disk (snapshots/txn log) In Quorum / leader election ports 2888/3888; QuorumPeernetwork, disk In Java client library ZooKeeper,ClientCnxnnetwork In AdminServer (embedded Jetty) HTTP 8080 /commands/*network In Four-letter-words (4lw) client port, telnet/nc network In Jute serialization BinaryInputArchive(wire decode)— In Dynamic reconfig reconfigAPI,/zookeeper/confignetwork In C/C++ client + C CLI ( cli_st)native lib network In (C client), see §3 for CLI zookeeper-contrib/*(REST, zooinspector, perl/python, zkfuse, …)varies varies Out — §3 zookeeper-recipes/*(locks, queues, election)sample code network Out — §3 zookeeper-specifications(TLA+)— — Out (formal spec, not shipped code) Anything marked Out reappears in §3 with the reason.
- Not a public-internet service. "A ZooKeeper ensemble is expected to operate in a trusted computing environment. It is thus recommended deploying ZooKeeper behind a firewall." (documented: zookeeperAdmin.md "Publicly accessible deployment") Threats that exist only because the ensemble was exposed to the open internet against this guidance are operator misconfiguration, not server vulnerabilities — but see §14, this boundary needs a sharp ruling.
- Not an attempt to defend against a malicious in-process caller of the Java client. A caller already inside the client JVM has the credentials and can do anything the session can; not a meaningful adversary at this layer. (inferred)
- No notion of znode ownership. "ZooKeeper does not have a notion of an owner of a znode." (documented: zookeeperProgrammers.md)
- ACLs are not recursive / not inherited. An ACL pertains only to a specific znode, not its children. (documented: zookeeperProgrammers.md) This is design, not a bug (see §9 false friends).
- Shipped-but-unsupported code, modelled separately or not at all:
zookeeper-contrib/*(REST gateway, ZooInspector, perl/python/C bindings, zkfuse, zktreeutil, loggraph, monitoring): separately authored, not part of the core security guarantee. A finding here isOUT-OF-MODEL: unsupported-componentunless the PMC says otherwise. (inferred — §14)zookeeper-recipes/*: reference implementations / sample code. (inferred — §14)- The C CLI shell (
cli_st) is an operator tool, not a server surface; historically a buffer-overflow site (CVE-2016-5017). Whether the C client library is in core scope vs. the CLI being a tool needs a ruling. (inferred — §14)
- Build/release/SDLC hygiene (action pinning, signing, dependency freshness) is out per the skill's §1.
- Primary trust boundary = the client port and the quorum port. Bytes arriving on either are untrusted wire input and are decoded by Jute before any ACL logic runs.
- The data tree is the protected asset. Access to a znode is mediated by
ZooKeeperServer.checkACL(code). Once a request passes the ACL check (or the node has a null/empty ACL, which short-circuits to allow), the operation executes. (code:ZooKeeperServer.javacheckACL) - Trust transitions:
- Wire bytes → Jute decode (request-size bounded by
jute.maxbuffer, default0xfffff≈ 1 MB) → request object. (code:BinaryInputArchive.java) - Request → session auth context (the set of
Ids the connection has accumulated viaaddAuthInfo/ SASL handshake / TLS cert). - Request + auth context →
checkACLagainst the target node's own ACL (for create/delete, against the parent's ACL). No walk up the tree. (code:PrepRequestProcessor.java)
- Wire bytes → Jute decode (request-size bounded by
- Reachability preconditions per family (the test a triager applies before anything else):
- Server-core finding: in-model only if reachable from a request a client can actually send on the client port given the configured auth posture.
- Quorum finding: in-model only if reachable from a peer on the quorum port — and only
VALIDif quorum auth is enabled (else it requires an attacker already on the quorum network, see §7). - AdminServer finding: in-model only if reachable via HTTP on the admin port.
- Jute finding: in-model only if reachable from attacker-supplied wire bytes within the
jute.maxbufferbound.
- Network: A trusted, firewalled datacenter network. Client, quorum, election, admin, and JMX ports are assumed reachable only by intended parties. (documented: Admin guide deployment section)
- Quorum integrity: A strict majority of configured servers are honest and available; ZAB safety/liveness assume crash-fault (not Byzantine) peers. (inferred — classic ZAB assumption — §14)
- Disk / persistence: The snapshot directory and transaction log are on storage the operator controls and trusts; on-disk data is not encrypted by ZooKeeper and snapshots/txn logs contain znode data (including digest ACL hashes) in the clear. (inferred — §14)
- Clock: Session expiry and leader-election timeouts rely on reasonably synchronized, monotonic-enough clocks;
tickTimedrives liveness. (documented: tickTime in Admin guide; inferred for the security implication) - JVM / runtime: A conformant JRE.
fips-mode(zookeeper.fips-mode) default true on 3.9.0+, false on 3.8.x; when enabled the customZKTrustManageris disabled, so quorum hostname verification is not available (client-server still is). (documented: zookeeperAdmin.md) - What ZooKeeper does to / does not do to its host (mostly negative claims, hence mostly
(inferred)— high-priority §14 confirmation targets):- It does open listening sockets (client, quorum, election, admin HTTP, optional JMX/metrics), read
zoo.cfgand system properties, read JAAS config and keystores, and write snapshots/txn logs to disk. (documented/code) - It honors a number of
zookeeper.*system properties that change the security envelope at JVM start (skipACL,superUser,4lw.commands.whitelist,ssl.*, etc.) — the security posture is partly a function of the JVM command line, not justzoo.cfg. (documented) - It does not spawn child processes or shell out as part of request handling. (inferred — §14)
- The
ipscheme over the AdminServer HTTP path honors a client-suppliedX-Forwarded-Forheader. (code:IPAuthenticationProvider) — this is the root of CVE-2024-51504.
- It does open listening sockets (client, quorum, election, admin HTTP, optional JMX/metrics), read
ZooKeeper is really a family of deployment postures. The knobs below change which §8 properties hold. Most ship in the less-secure default, which is the central tension this model must resolve with the PMC (§14).
| Knob | Default | Effect on model | Maintainer stance |
|---|---|---|---|
zookeeper.skipACL |
no |
yes disables all ACL checks → full data-tree access for any client; also unauthenticated reconfig. (documented) |
dev-only? §14 |
Client authentication (OPEN_ACL_UNSAFE nodes, no auth provider) |
open | With no ACLs/auth, any client reads/writes any node. (code/docs) | §14 |
zookeeper.sessionRequireClientSASLAuth |
false |
true rejects non-SASL-authenticated clients. (documented) |
§14 |
zookeeper.enforce.auth.enabled + enforce.auth.schemes |
false |
true requires the listed auth schemes per session. (documented) |
§14 |
sslQuorum (zookeeper.sslQuorum) |
false |
quorum + election traffic plaintext & unauthenticated unless on. (documented) | §14 |
quorum.auth.serverRequireSasl / learnerRequireSasl / enableSasl |
false |
quorum SASL off; peers unauthenticated. (code: QuorumPeerConfig) | §14 |
secureClientPort / client TLS |
unset | client traffic plaintext unless configured. (documented) | §14 |
ssl.clientAuth / ssl.quorum.clientAuth |
need |
when TLS is on, client cert is required (good default). (documented) | — |
ssl.hostnameVerification / ssl.quorum.hostnameVerification |
true |
disabling enables MITM; "only recommended for testing." (documented) | — |
reconfigEnabled |
false |
true allows runtime membership change via API. (documented) |
§14 |
4lw.commands.whitelist |
only srvr (+isro if RO mode) |
wildcard * exposes all 4lw incl. info-disclosing/expensive ones. (documented/code) |
— |
admin.enableServer |
true |
embedded Jetty AdminServer on 0.0.0.0:8080, most commands unauthenticated. (documented/code) |
§14 |
admin.needClientAuth / admin.forceHttps / admin.portUnification |
false |
admin HTTP is plaintext, no client auth, unless set. (documented) | §14 |
zookeeper.DigestAuthenticationProvider.digestAlg |
SHA1 |
unsalted; "will be deprecated for security issues." (documented) | — |
fips-mode |
true (3.9+) / false (3.8) |
when true, disables ZKTrustManager → no quorum hostname verification. (documented) |
— |
Insecure-default ruling needed (wave 1, §14): for every row marked "§14", the model is ambiguous until the PMC rules whether the default is the supported production posture (report against it = VALID) or a dev-convenience operators must flip (= OUT-OF-MODEL: non-default-build, and the requirement moves to §10).
ZooKeeper accepts: (a) client requests on the client port, (b) quorum/election messages on the quorum ports, (c) HTTP requests on the AdminServer, (d) 4lw strings on the client port, (e) zoo.cfg / dynamic config / system properties from the operator (trusted).
Per-parameter trust table (route/message-oriented, as for a network service):
| Surface / message | Parameter | Attacker-controllable? | Caller/operator must enforce |
|---|---|---|---|
| Client request (any op) | request bytes / path / data | yes (untrusted client) | size ≤ jute.maxbuffer; ACLs on nodes; enable auth if clients are untrusted |
create / setData |
znode data blob |
yes | quota (setquota); znode size; ACL on parent |
create/setACL |
ACL list | yes | meaningful (non-OPEN_ACL_UNSAFE) ACLs if multi-tenant |
getChildren / watches |
path, watch registration | yes | READ perm on node (note CVE-2024-23944 persistent-watcher leak) |
addAuthInfo (digest) |
user:password |
yes | sent cleartext → use only over TLS/localhost (documented) |
ip scheme |
source IP | spoofable (and X-Forwarded-For on HTTP path) |
network-level controls; do not rely on ip across untrusted nets |
| Quorum / election message | peer wire bytes | yes if quorum net is reachable | enable quorum SASL/TLS; firewall quorum ports |
| AdminServer | HTTP path /commands/<cmd>, headers |
yes if admin port reachable | restrict admin port; needClientAuth+TLS for x509 |
| 4lw | 4-char command string | yes if whitelisted | keep whitelist minimal; firewall |
zoo.cfg, JAAS, keystores, zookeeper.* sysprops |
all | no — operator-trusted | protect these files / JVM args |
- Size / shape: A single request/response is bounded by
jute.maxbuffer(default ~1 MB;BinaryInputArchive.maxBuffer), withzookeeper.jute.maxbuffer.extrasizeslack. (code)maxClientCnxnsdefault 60 per IP;maxCnxnsdefault 0 (unlimited). (documented)
- In-scope adversary: the unauthenticated/low-privilege network client that can reach the client port. Capabilities: open sessions, send arbitrary (size-bounded) requests, register watches, run whitelisted 4lw, attempt auth. Goals: read/modify data it should not, exhaust resources, crash a server, leak session/config info. (inferred — §14)
- In-scope adversary: HTTP client reaching the AdminServer — can invoke unauthenticated commands (info disclosure) and, where snapshot/restore auth is weak, more. (documented via CVE-2025-58457 / CVE-2024-51504 patterns)
- Authenticated-but-Byzantine peer (distributed-system actor): a server that holds a legitimate quorum identity, passes the handshake, then behaves arbitrarily. ZAB tolerates crash faults of a minority, not Byzantine faults. Safety holds while a strict majority are honest and available; with
> n/2faulty/colluding peers, the model breaks. The complement (≥majority Byzantine, or a forged-identity peer when quorum auth is off) is out of scope → §3. (inferred — §14; this threshold must be stated by the PMC) - Out of scope:
- An attacker with operator privileges (owns
zoo.cfg, JAAS, keystores, disk, JVM args). They have already won. (inferred — §14) - An attacker already on the quorum/election network when quorum auth is off — this is the documented "trusted network" assumption (§5); such an attacker can impersonate a peer. A report requiring this is
OUT-OF-MODEL: adversary-not-in-scopeonly if the PMC affirms quorum-off is a supported posture (else it isVALID). (inferred — §14) - Side-channel / timing / co-tenant memory adversaries against the JVM. (inferred — §14)
- On-disk attacker reading snapshots/txn logs (no at-rest encryption claim). (inferred — §14)
- An attacker with operator privileges (owns
Each property states: the property + conditions, violation symptom, severity tier, provenance. All (inferred) here are proposals pending PMC confirmation (§14).
- ACL-mediated access control on individual znodes. Conditions: a non-trivial ACL is set on the node, the matching auth provider is configured, and
skipACL=no. A request lacking the required permission is rejected withNoAuth. Symptom of violation: a client reads/writes a node without holding the requiredId/permission. Severity: security-critical (auth bypass → CVE). (documented/code:checkACL) - Authentication via configured schemes (
digest,sasl/Kerberos,x509/mTLS). Conditions: provider enabled; fordigest, channel confidentiality is the caller's job. Symptom: identity accepted that should not be (e.g. SASL quorum bypass = CVE-2023-44981). Severity: security-critical. (documented/code) - Optional transport confidentiality & integrity (TLS) for client-server (
secureClientPort) and quorum (sslQuorum), with hostname verification on by default and client-cert authneedby default when TLS is enabled. Symptom: plaintext exposure or accepted MITM cert (cf. CVE-2026-24281, CVE hostname-bypass). Severity: security-critical when TLS is configured and the guarantee is breached. (documented) - Replicated-state safety (linearizable writes, FIFO client order) under ZAB, given a majority of honest, available, crash-only servers. Symptom: divergent state across replicas / lost or reordered committed writes / a fork. Severity: security-critical if reachable by an in-scope adversary; otherwise correctness. (inferred — §14; this is ZAB's documented design but the security framing needs PMC sign-off)
- Bounded per-request size. Requests/responses exceeding
jute.maxbuffer(default ~1 MB) are rejected at decode. Symptom: unbounded allocation from a single message. Severity: security-relevant DoS guard. (code) - Connection rate limiting per source IP via
maxClientCnxns(default 60). Symptom: single IP exhausts connection slots. Severity: partial DoS guard. (documented) - Quota accounting with optional hard enforcement. Soft quota warns only; hard quota throws
QuotaExceededException. Symptom: a tenant exceeds count/byte limits silently (soft) — by design. Severity: correctness / operational, not a memory-safety guarantee. (documented: zookeeperQuotas.md) - Audit logging of mutating operations when enabled (
ZKAuditProvider). Symptom: a mutating op leaves no audit trail when auditing is on. Severity: detective control, not preventive. (code:audit/)
Resource note: ZooKeeper makes no general guarantee of bounded total memory or CPU under adversarial request mixes beyond the per-request
jute.maxbuffercap and connection limits. The data tree is held in memory; aggregate size is bounded by quotas only if hard quotas are set. See §9. (inferred — §14)
This is the highest-value section for an integrator. State plainly:
- No secure-by-default posture. Out of the box, with
OPEN_ACL_UNSAFEnodes and no auth provider, any client that reaches the port can read and write the entire data tree. Authentication and ACLs are opt-in. (documented/code) - No on-the-wire encryption by default. Client and quorum traffic are plaintext unless TLS is explicitly configured.
digestcredentials travel in cleartext. (documented) - No quorum authentication by default. Peer and leader-election traffic is unauthenticated unless quorum SASL or quorum TLS is enabled. (documented/code)
- No at-rest encryption. Snapshots and transaction logs store znode data (and digest ACL hashes) unencrypted. (inferred — §14)
- No Byzantine fault tolerance. A malicious peer holding a valid identity, or a majority of faulty peers, can violate safety. (inferred — §14)
- No defense against a malicious/over-privileged client beyond ACLs. ZooKeeper will not protect node A from client B if B holds (or can spoof) the credentials A's ACL trusts.
- No general resource-exhaustion guarantee. Watches, connections, and tree size driven by clients can pressure heap/CPU; only per-request size, per-IP connection count, and (opt-in) hard quotas bound this. Expensive 4lw (
wchc/wchp/dump) and large watch sets are a known DoS vector (CVE-2017-5637). (documented/inferred — §14)
False friends (features mistaken for security primitives):
ipauthentication scheme — looks like authentication; it is source-IP matching, trivially spoofable on an untrusted network, and over the AdminServer HTTP path it trusts a client-suppliedX-Forwarded-Forheader. Not an authentication boundary across untrusted networks. (code; CVE-2024-51504)digestscheme — looks like password auth; the password is sent cleartext and stored as an unsalted SHA1 hash. Confidentiality is entirely the transport's job. (documented)- ACLs are NOT recursive — setting a restrictive ACL on
/appdoes not protect/app/status; a world-readable child stays world-readable. An integrator who "locks down a subtree" by ACL-ing the root has not locked anything below it. (documented) world:anyone— the conventional defaultId; means no access control.- Quotas are not a security boundary by default — soft quota only logs; it does not stop a tenant from filling memory. (documented)
- The
authscheme insetACLgrants to whatever the setter authenticated as, not a named principal — easy to mis-reason about. (documented)
Well-known attack classes left to the operator/integrator (one line each, integrator-on-notice):
- DoS via expensive operations / large watch sets / connection floods — mitigate with whitelist,
maxClientCnxns, quotas, firewalling. - Information disclosure via 4lw and AdminServer (
envi,conf,cons,dump,mntr) — unauthenticated when reachable. - MITM on plaintext channels — mitigate with TLS + hostname verification.
- Credential theft on plaintext
digest— mitigate with TLS. - Reconfig abuse (adding a rogue server / removing quorum members) when
reconfigEnabled=trueand ACLs/auth are weak. (documented: zookeeperReconfig.md)
For ZooKeeper "user" = operator/deployer. To make the §5–§7 assumptions hold:
- Deploy inside a trusted, firewalled network. Do not expose client (2181), quorum (2888), election (3888), admin (8080), JMX, or metrics ports to untrusted networks. (documented)
- If clients are not fully trusted, set meaningful ACLs (not
OPEN_ACL_UNSAFE) and enable authentication (sessionRequireClientSASLAuthorenforce.auth.*). ACLs alone onOPEN_ACL_UNSAFEtrees protect nothing. - Set ACLs on every sensitive node, including children — ACLs do not inherit.
- Use TLS (
secureClientPort/sslQuorum) whenever traffic crosses a link you do not fully trust; never disable hostname verification in production. Usedigestonly over TLS or localhost. - Enable quorum authentication (quorum SASL and/or quorum TLS) — it is off by default.
- Restrict the AdminServer: disable it (
admin.enableServer=false) if unused, or bind/firewall it and require client auth + HTTPS; assume most commands are unauthenticated otherwise. - Keep the 4lw whitelist minimal; do not set
*on an exposed instance. - Leave
skipACL=noin any environment where the client port is reachable by untrusted parties. - Protect
zoo.cfg, JAAS files, keystores, super-user digests, and the snapshot/txn-log directory at the OS level — these are the operator-trusted inputs and the unencrypted data at rest. - Guard
reconfigEnabledand the/zookeeper/configwrite ACL; keep reconfig off unless needed and authenticated.
- Treating ZooKeeper as internet-facing. Binding to a public interface with default config exposes the whole data tree. What it looks like: 2181 open to the world. Why unsafe: no auth by default. Instead: firewall + auth + TLS.
OPEN_ACL_UNSAFEin production multi-tenant trees. Why unsafe: any client can mutate/delete. Instead: per-node ACLs + auth.- ACL-ing only the root of a subtree. Relying on a parent ACL to protect children. Instead: set ACLs on each node; ACLs are not recursive.
- Relying on the
ipscheme across untrusted networks, or behind a proxy that setsX-Forwarded-For. Instead: SASL/x509. digestover plaintext. Leaks credentials. Instead: TLS or localhost only.- Leaving quorum auth/TLS off on a shared network. Allows peer impersonation / reconfig abuse. Instead: quorum SASL + TLS.
- Setting
4lw.commands.whitelist=*or exposing the AdminServer for convenience. Leaks config/session/watch data. Instead: minimal whitelist, restricted admin port. skipACL=yesfor throughput. Opens full data-tree access (and unauthenticated reconfig). Instead: never with an untrusted client port.
Patterns tools/researchers repeatedly report that are not bugs under this model (cite the licensing section):
- "Anyone can read/write — no auth!" against a default config — by design; auth/ACLs are opt-in per §9, and exposure presupposes the operator violated §10.1. →
BY-DESIGN/OUT-OF-MODEL: trusted-inputdepending on framing (PMC to set, §14). - "
world:anyoneACL is insecure." It is the documented open ACL; using it is a §11 misuse, not a server defect. →KNOWN-NON-FINDING(§9). - "Child znode readable despite restrictive parent ACL." ACLs are not recursive by design. →
BY-DESIGN(§9). (documented) - "
digestpassword sent in cleartext." Documented; transport security is the caller's job. →BY-DESIGN(§9). (documented) - "4lw / AdminServer command leaks environment/config." Whitelisted/enabled by the operator; exposure presupposes §10 was violated. →
OUT-OF-MODEL: trusted-inputorKNOWN-NON-FINDING(PMC, §14). - "Quorum traffic unauthenticated/plaintext." Default posture; trusted-network assumption (§5). Whether reportable depends on the §14 quorum-default ruling.
- "Unsalted SHA1 in digest hash." Known/documented limitation; →
BY-DESIGNpending the planned algorithm migration. (documented)
Note: this list assumes the PMC affirms the "trusted network / opt-in auth" posture. If instead the PMC declares secure-by-default the supported posture, several of these flip to
VALID. This single ruling reshapes §8/§9/§11a/§13 — it is the top §14 question.
- A new public API, request type, or wire-format change.
- A new network surface (new listener/port) or a change in a default (e.g. another
fips-mode-style flip, enabling auth by default, AdminServer auth-by-default). - Promotion of a
contrib/orrecipes/component into supported core. - Adoption of at-rest encryption, BFT, or secure-by-default — any of which would rewrite §8/§9.
- Evidence of incompleteness: any report that cannot be routed to exactly one §13 disposition is a
MODEL-GAPand triggers a revision (add the property to §8/§9), not an ad-hoc call.
| Disposition | Meaning | Licensed by |
|---|---|---|
VALID |
Violates a claimed property via an in-scope adversary and input. | §8, §6, §7 |
VALID-HARDENING |
No §8 property violated, but a §11 misuse is easy enough to warrant hardening. Private report, fixed at maintainer discretion, usually no CVE. | §11 |
OUT-OF-MODEL: trusted-input |
Requires attacker control of an input the model marks trusted (e.g. zoo.cfg, operator sysprops, a node the report assumes should be auth'd but the operator left open). |
§6 |
OUT-OF-MODEL: adversary-not-in-scope |
Requires a capability the model excludes (operator privilege, on-quorum-network when quorum-off is supported, side channel, on-disk). | §7 |
OUT-OF-MODEL: unsupported-component |
Lands in contrib/, recipes/, or other §3 code. |
§3 |
OUT-OF-MODEL: non-default-build |
Manifests only under a discouraged/non-default §5a knob the PMC ruled dev-only. | §5a |
BY-DESIGN: property-disclaimed |
Concerns a §9-disclaimed property (non-recursive ACLs, cleartext digest, no at-rest encryption, etc.). | §9 |
KNOWN-NON-FINDING |
Matches a §11a recurring false positive. | §11a |
MODEL-GAP |
Cannot be cleanly routed above → revise the model. | triggers §12 |
Grouped in waves; each states a proposed answer to confirm/correct. Wave 1 reshapes the most.
Wave 1 — the secure-by-default question (reshapes §3, §7, §8, §9, §11a, §13):
- Proposed: "The supported production posture is opt-in security on a trusted, firewalled network: default open ACLs / no client auth / plaintext / quorum-auth-off are supported defaults, and a report that merely observes them (without the operator following §10) is
OUT-OF-MODEL: trusted-input, notVALID." Confirm, or declare secure-by-default the supported posture. (Lands: §3, §7, §9, §11a.) - Proposed: "An attacker on the quorum/election network while quorum auth is off is out of scope (trusted-network assumption)." Confirm, or rule quorum-off a dev-only posture (then peer-impersonation reports become
VALID). (Lands: §5a, §7, §13.) - Proposed: "
skipACL=yesis dev/benchmark-only; reports requiring it areOUT-OF-MODEL: non-default-build." Confirm. (Lands: §5a, §10, §13.)
Wave 2 — scope of shipped code:
4. Proposed: "zookeeper-contrib/* and zookeeper-recipes/* are out of the core security model (separately authored / sample code); findings are OUT-OF-MODEL: unsupported-component." Confirm per-component, especially the REST gateway and ZooInspector. (Lands: §2, §3.)
5. Proposed: "The C client library is in core scope, but the C CLI shell (cli_st) is an operator tool, not a server surface." Confirm. (Lands: §2, §3.)
Wave 3 — environment / negative claims (mostly (inferred)):
6. Proposed: "ZooKeeper performs no at-rest encryption; protecting the snapshot/txn-log directory is an operator responsibility." Confirm. (Lands: §5, §9, §10.)
7. Proposed: "Request handling never spawns child processes / shells out." Confirm. (Lands: §5.)
8. Proposed: "ZAB assumes crash-fault, non-Byzantine peers; safety holds with a strict honest majority (> n/2 honest)." Confirm the threshold wording for §7/§8. (Lands: §7, §8.)
Wave 4 — property severities and DoS line:
9. Proposed: "There is no general bounded-memory/CPU guarantee under adversarial request mixes beyond jute.maxbuffer + maxClientCnxns + opt-in hard quotas; a hang or super-linear blowup driven by a single bounded request is a bug, but heap pressure from many legitimate-looking requests/watches is an operational concern, not a CVE." Confirm the DoS line for §8/§9/§13. (Lands: §8, §9.)
10. Proposed: "Replicated-state safety violations (forks, lost committed writes) are security-critical; liveness/availability degradation under load is correctness/operational." Confirm severity tiers. (Lands: §8.)
Wave 5 — meta:
11. Where should this document live and how should it be versioned with releases — zookeeper-docs/.../threatModel.md published on the site, or repo-root draft? Should it be linked from security.html?
12. Is there any existing internal threat-model or security-design note (PMC-private) this should be reconciled against as a (documented) source?
A sidecar (threat-model.yaml) for automated triage is deferred until §14 wave 1 is resolved, since the disposition of the default-posture findings determines almost every in_scope flag. Once ratified, emit: entry points → per-parameter trust (from §6); component families → in/out (§2/§3); §5a knobs → security-relevant/default/stance; §8 properties → severity + violation symptom; §9 disclaimed + false friends; §11a non-findings; §13 labels. The prose remains canonical.
| Source statement | Lands in |
|---|---|
| "report to security@zookeeper.apache.org before disclosing" | §1 reporting cross-ref |
| "expected to operate in a trusted computing environment … behind a firewall" | §3, §5, §10.1 |
| "ACLs are not recursive" | §3, §9 false friends |
| "no notion of an owner of a znode" | §3 |
| digest "sent in clear text" / "plaintext" | §6, §9 |
skipACL "opens up full access to the data tree to everyone" |
§5a, §9, §10 |
| reconfig "any unauthenticated users can use reconfig API" (with skipACL) | §5a, §11 |
4lw.commands.whitelist default srvr |
§5a, §6, §11a |
fips-mode disables quorum hostname verification |
§5, §5a |
| quota soft vs hard semantics | §8 |
| CVE history (IP-auth bypass, SASL quorum bypass, persistent-watcher leak, 4lw DoS, hostname-verification bypass) | informs §7, §9, §11a (patterns, not a CVE list) |