Skip to content

Instantly share code, notes, and snippets.

@ppkarwasz
Last active June 18, 2026 19:19
Show Gist options
  • Select an option

  • Save ppkarwasz/f5be1b5c0182fe665252101c5f24d39f to your computer and use it in GitHub Desktop.

Select an option

Save ppkarwasz/f5be1b5c0182fe665252101c5f24d39f to your computer and use it in GitHub Desktop.
Draft Zookeeper threat model

Apache ZooKeeper — Threat Model

Produced with the threat-model-producer skill (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.

§1 Header

  • Project: Apache ZooKeeper (server + Java client + Jute serialization).
  • Version / commit: 3.10.0-SNAPSHOT, commit 9b535738d (branch fix/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-mode flipped 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.org per 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.

§2 Scope and intended use

  • 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, DataTree network, disk (snapshots/txn log) In
    Quorum / leader election ports 2888/3888; QuorumPeer network, disk In
    Java client library ZooKeeper, ClientCnxn network 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 reconfig API, /zookeeper/config network 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.

§3 Out of scope (explicit non-goals)

  • 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 is OUT-OF-MODEL: unsupported-component unless 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.

§4 Trust boundaries and data flow

  • 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.java checkACL)
  • Trust transitions:
    • Wire bytes → Jute decode (request-size bounded by jute.maxbuffer, default 0xfffff ≈ 1 MB) → request object. (code: BinaryInputArchive.java)
    • Request → session auth context (the set of Ids the connection has accumulated via addAuthInfo / SASL handshake / TLS cert).
    • Request + auth context → checkACL against the target node's own ACL (for create/delete, against the parent's ACL). No walk up the tree. (code: PrepRequestProcessor.java)
  • 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 VALID if 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.maxbuffer bound.

§5 Assumptions about the environment

  • 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; tickTime drives 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 custom ZKTrustManager is 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.cfg and 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 just zoo.cfg. (documented)
    • It does not spawn child processes or shell out as part of request handling. (inferred — §14)
    • The ip scheme over the AdminServer HTTP path honors a client-supplied X-Forwarded-For header. (code: IPAuthenticationProvider) — this is the root of CVE-2024-51504.

§5a Build-time and configuration variants (the security envelope is a function of config)

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).

§6 Assumptions about inputs

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), with zookeeper.jute.maxbuffer.extrasize slack. (code) maxClientCnxns default 60 per IP; maxCnxns default 0 (unlimited). (documented)

§7 Adversary model

  • 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/2 faulty/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-scope only if the PMC affirms quorum-off is a supported posture (else it is VALID). (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)

§8 Security properties the project provides

Each property states: the property + conditions, violation symptom, severity tier, provenance. All (inferred) here are proposals pending PMC confirmation (§14).

  1. 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 with NoAuth. Symptom of violation: a client reads/writes a node without holding the required Id/permission. Severity: security-critical (auth bypass → CVE). (documented/code: checkACL)
  2. Authentication via configured schemes (digest, sasl/Kerberos, x509/mTLS). Conditions: provider enabled; for digest, 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)
  3. Optional transport confidentiality & integrity (TLS) for client-server (secureClientPort) and quorum (sslQuorum), with hostname verification on by default and client-cert auth need by 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)
  4. 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)
  5. 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)
  6. Connection rate limiting per source IP via maxClientCnxns (default 60). Symptom: single IP exhausts connection slots. Severity: partial DoS guard. (documented)
  7. 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)
  8. 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.maxbuffer cap 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)

§9 Security properties the project does NOT provide

This is the highest-value section for an integrator. State plainly:

  • No secure-by-default posture. Out of the box, with OPEN_ACL_UNSAFE nodes 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. digest credentials 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):

  • ip authentication 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-supplied X-Forwarded-For header. Not an authentication boundary across untrusted networks. (code; CVE-2024-51504)
  • digest scheme — 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 /app does 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 default Id; 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 auth scheme in setACL grants 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=true and ACLs/auth are weak. (documented: zookeeperReconfig.md)

§10 Downstream responsibilities (the operator's contract)

For ZooKeeper "user" = operator/deployer. To make the §5–§7 assumptions hold:

  1. 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)
  2. If clients are not fully trusted, set meaningful ACLs (not OPEN_ACL_UNSAFE) and enable authentication (sessionRequireClientSASLAuth or enforce.auth.*). ACLs alone on OPEN_ACL_UNSAFE trees protect nothing.
  3. Set ACLs on every sensitive node, including children — ACLs do not inherit.
  4. Use TLS (secureClientPort / sslQuorum) whenever traffic crosses a link you do not fully trust; never disable hostname verification in production. Use digest only over TLS or localhost.
  5. Enable quorum authentication (quorum SASL and/or quorum TLS) — it is off by default.
  6. 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.
  7. Keep the 4lw whitelist minimal; do not set * on an exposed instance.
  8. Leave skipACL=no in any environment where the client port is reachable by untrusted parties.
  9. 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.
  10. Guard reconfigEnabled and the /zookeeper/config write ACL; keep reconfig off unless needed and authenticated.

§11 Known misuse patterns

  • 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_UNSAFE in 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 ip scheme across untrusted networks, or behind a proxy that sets X-Forwarded-For. Instead: SASL/x509.
  • digest over 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=yes for throughput. Opens full data-tree access (and unauthenticated reconfig). Instead: never with an untrusted client port.

§11a Known non-findings (recurring false positives)

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-input depending on framing (PMC to set, §14).
  • "world:anyone ACL 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)
  • "digest password 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-input or KNOWN-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-DESIGN pending 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.

§12 Conditions that would change this model

  • 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/ or recipes/ 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-GAP and triggers a revision (add the property to §8/§9), not an ad-hoc call.

§13 Triage dispositions (closed set)

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

§14 Open questions for the maintainers

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):

  1. 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, not VALID." Confirm, or declare secure-by-default the supported posture. (Lands: §3, §7, §9, §11a.)
  2. 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.)
  3. Proposed: "skipACL=yes is dev/benchmark-only; reports requiring it are OUT-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?

§15 Optional: machine-readable companion

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.


Appendix — security.html / docs back-map (coverage proof)

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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment