Status: v1.0 — accepted (technical content). Pending wave-4 process items. Wave-1/2/3/4 maintainer interviews completed 2026-05-14 (Doris committer morningman). All technical
(inferred)tags from v0.1 have been resolved or consciously deferred. Amended 2026-07-29 with wave 5 (M19, FEenable_all_http_auth/ HTTP auth posture).
This document is the security contract for Apache Doris: what the project assumes, what it guarantees given those assumptions, what it explicitly leaves to the operator, and how a vulnerability triager should classify any inbound report.
master at commit 1d1846591f7, 2026-05-14. Per M15 (single-living-doc policy), the model-version field at the top of this file is bumped per minor release; vulnerability reports against project version N are triaged against the model as it stood at N (read the file at the matching git tag).security@apache.org (ASF security team will route to Doris). A short SECURITY.md at the repo root links to this document as canonical scope (M16 (A)). Findings that fall under §4.3 / §4.9 / §4.11a will be closed with a citation to this document.SECURITY.md coexistence artifact is complete, while model-version field policy text remains follow-up work.conf/*.conf, or user docsQ1–Q8 are wave-1/2 questions; M1–M18 are wave-3/4 questionsOne-paragraph project description. Apache Doris is an MPP analytical (OLAP) database. Clients submit SQL over the MySQL wire protocol or Arrow Flight; queries are parsed and planned by the FE (Frontend, Java) and executed by the BE (Backend, C++) against locally managed columnar storage and/or external lakehouse catalogs (Hive, Iceberg, Hudi, Paimon, JDBC, S3/HDFS/Azure). Doris ships in two deployment shapes: classic on-prem (FE+BE+Broker), and the cloud-native cloud/ variant (storage-compute disaggregated, shared Meta Service, K8s-native, multi-tenant). Both are in-model; content that differs is marked [on-prem] / [cloud].
Primary intended use — In-cluster MPP execution of analytical SQL, where the cluster is operated by the same organization that controls its network perimeter (maintainer, Q2).
Deployment shapes in scope (maintainer, Q2):
cloud/ directory; storage-compute disaggregated, K8s-native. Tenancy model: Meta Service is shared across tenants; per-tenant isolation enforced inside Meta Service is a security claim of the project (maintainer, M2). Cross-tenant data leak / privilege escalation through Meta Service is VALID, not OUT-OF-MODEL.Deployment shape explicitly OUT of scope (maintainer, Q2):
Caller roles:
| Role | Trust level | In §4.7? |
|---|---|---|
| Anonymous network attacker on client-facing ports (MySQL 9030, HTTP 8030, FE Arrow Flight 8070, BE Arrow Flight 8050) | Untrusted | Yes — primary pre-auth adversary |
| Authenticated SQL user with limited RBAC privileges | Untrusted within RBAC scope | Yes — primary post-auth adversary |
Authenticated user holding CREATE CATALOG (sub-admin) | Untrusted within RBAC; can attach external URL endpoints | Yes (maintainer, M13) — narrow SSRF actor; see §4.9 |
Authenticated user in tenant T₁ trying to reach tenant T₂ data [cloud] | Untrusted across tenant boundary | Yes (maintainer, M2) — cross-tenant adversary |
SUPER / ADMIN_PRIV / database owner / operator-level user | Trusted (maintainer, M3) | No |
| Cluster-internal RPC peer (FE↔BE, BE↔BE, FE↔Follower, FE↔Broker, FE↔MetaService) | Trusted by network isolation (maintainer, Q1) | No |
| External catalog / storage system (Hive Metastore, Iceberg, JDBC source, S3, HDFS, Azure Blob) | Trusted by admin connection (maintainer, Q8) | No |
Component-family table. Distinct threat profiles. Surface lists ports / inputs each family exposes; In model? ties to §4.3.
| # | Family | Path | Surface | In model? |
|---|---|---|---|---|
| 1 | FE core (Java) | fe/fe-core/ | MySQL 9030, HTTP 8030, FE Arrow Flight 8070 (client); RPC 9020, Edit-log 9010 (internal) | Yes |
| 2 | BE core (C++) | be/src/ | BE Arrow Flight 8050 (client-facing, M7); BRPC 8060, Webserver 8040, Heartbeat 9050, BE↔BE 9060 (internal) | Yes |
| 3 | Cloud variant | cloud/src/ | Meta Service (shared, multi-tenant), Recycler, Resource Manager | Yes (maintainer, Q2, M2) |
| 4 | FE auth providers | fe/fe-authentication/ | Pluggable: native, LDAP | Yes |
| 5 | FE connectors (catalogs) | fe/fe-connector/{iceberg,hudi,hms,jdbc,paimon,trino,maxcompute,es} | Outbound to external systems; in-process JAR loading | Yes (memory safety only; data trusted per §4.6) |
| 6 | BE Java extensions | fe/be-java-extensions/ | In-process JVM in BE | Yes (memory safety; UDF code trusted per §4.6) |
| 7 | HDFS / FS broker client | fe/fe-filesystem/fe-filesystem-broker/ | Thrift RPC to external broker (cluster-internal); the in-tree apache_hdfs_broker daemon has been removed | Yes (internal trust per §4.4) |
| 8 | Web UI | ui/ + webroot/ | Served via FE 8030 (auth gated) | Yes |
| 9 | Vendored MySQL source | mysql/mysql-{9.4.0,9.5.0}/ | None (reference only, not built or shipped) | No (maintainer, Q4) |
| 10 | Sample / dev / CI | samples/, docker/, pytest/, regression-test/, jdbc-version-test/, task_executor_simulator/, hooks/, build-support/ | None at runtime | No (maintainer, Q4) |
| 11 | All FE plugins | fe_plugins/ (auditdemo, auditloader, sparksql-converter, trino-converter) | FE plugin SPI | No (maintainer, Q4, M4) — auditloader included; users opting in take ownership |
| 12 | Client SDKs / extensions / CDC client | extension/, cdc_client (Doris SDKs now maintained out-of-tree in a separate doris-sdk repo) | Client-side libraries | No (maintainer, Q4) — separately versioned |
Use cases not supported.
NetworkPolicy, equivalent).exec_mem_limit (per-query memory cap), Workload Group (CREATE WORKLOAD GROUP ... — recommended production posture for memory/CPU/ concurrency caps per user/group), and max_connections / max_connection_per_user (FE config, prevent connection exhaustion).OUT-OF-MODEL: trusted-input.SUPER-privileged adversary (maintainer, M3). SUPER (and ADMIN_PRIV / equivalent) holders are trusted by definition. RCE achievable only after acquiring SUPER — UDF install, JDBC driver attach, FE plugin registration, ADMIN SET CONFIG — OUT-OF-MODEL: adversary-not-in-scope.BY-DESIGN: property-disclaimed (§4.9).numFailedLogin = 0 and passwordLockSeconds = 0 — the mechanism exists but is opt-in per user via CREATE USER ... FAILED_LOGIN_ATTEMPTS N PASSWORD_LOCK_TIME T. “I brute-forced an account in default config” is BY-DESIGN: property-disclaimed plus an §4.10 obligation.Code shipped but not threat-modeled. Family rows 9–12 (vendored MySQL, samples/dev/CI, all FE plugins including auditloader, SDK/extension/CDC) per §4.2. Reports landing there are OUT-OF-MODEL: unsupported-component.
Three concentric trust zones, with a tenant boundary inside Meta Service for cloud (maintainer, Q1, Q8, M2):
┌──────────────────────────────────────────────────────────────────────┐ │ Zone-3 EXTERNAL (Hive, Iceberg, Hudi, Paimon, JDBC, S3, │ │ HDFS, Azure) │ │ ── trusted-by-admin-connection ── │ │ ┌──────────────────────────────────────────────────────────────┐ │ │ │ Zone-2 CLUSTER-INTERNAL (FE↔FE, FE↔BE, BE↔BE, FE↔Broker, │ │ │ │ FE↔MetaService [cloud]) │ │ │ │ ── trusted-by-network-isolation ── │ │ │ │ ┌─────────────────────────────────────────────────┐ │ │ │ │ │ Zone-1 CLUSTER-CORE PROCESS │ │ │ │ │ │ FE JVM, BE C++ process, │ │ │ │ │ │ Cloud Meta Service ←── enforces tenant │ │ │ │ │ │ boundary T1│T2│T3 │ │ │ │ │ └─────────────────────────────────────────────────┘ │ │ │ └──────────────────────────────────────────────────────────────┘ │ │ │ │ ▲ THE BOUNDARY ▲ │ │ │ │ Zone-0 CLIENT (untrusted MySQL/HTTP/Arrow-Flight clients) │ │ ── BE Arrow Flight 8050 lives here too (M7) ── │ └──────────────────────────────────────────────────────────────────────┘
The single load-bearing trust transition is Zone-0 → Zone-1 at the client-facing ports. All other transitions assume the source is trusted. The cloud Meta Service additionally claims a tenant boundary inside Zone-1 — see §4.8 (NEW property).
Per-port reachability precondition. A finding in code reachable only from Zone-2 or Zone-3 inputs is OUT-OF-MODEL by §4.3 (2) or (5). Triage applies this test before anything else.
| Port | Protocol | Zone | Reachability precondition |
|---|---|---|---|
| FE 9030 | MySQL wire | 0→1 | bytes attacker-controlled before / during auth, or SQL post-auth |
| FE 8030 | HTTP / REST | 0→1 | request bytes attacker-controlled |
| FE 8070 | Arrow Flight (FE) | 0→1 | handshake / auth bytes attacker-controlled |
| BE 8050 | Arrow Flight (BE, client-facing) | 0→1 (maintainer, M7) | handshake bytes / result-stream consumption attacker-controlled |
| FE 9020 | Thrift RPC (FE↔BE) | 2 | none — out of model |
| FE 9010 | BDB JE edit log (FE↔Follower) | 2 | none — out of model |
| BE 8060 | BRPC | 2 | none — out of model |
| BE 8040 | HTTP webserver / metrics | 2 | none — out of model |
| BE 9050 | Thrift heartbeat (FE→BE) | 2 | none — out of model |
| BE 9060 | Thrift fragment exec (BE↔BE) | 2 | none — out of model |
| Broker | Thrift | 2 | none — out of model |
| Cloud Meta Service ↔ FE/BE | gRPC | 2 (network) + tenant-boundary (data) | a finding inside Meta Service is in-model if it crosses the per-tenant boundary |
Data flow from Zone-3 (external catalogs) into Zone-1. Per §4.3 (5) and §4.6, all bytes from external systems are admin-trusted. They flow into BE format readers (Parquet, ORC, Avro, JSON, CSV) and FE catalog metadata (HMS tables, Iceberg manifests). Crafted-byte crashes are OUT-OF-MODEL.
Supported toolchain / platform (maintainer, M8):
OUT-OF-MODEL: non-default-build.Operational assumptions:
storage_root_path directories; concurrent external mutation is undefined.Negative claims (what Doris does NOT do to its host) (maintainer, M9 — code-verified):
fork()), Python venv creation (system()), Broker shell utilities (popen()), and CDC client (fork()). No other arbitrary subprocess execution.DORIS_HOME, LOG_DIR, PID_DIR, HADOOP_CONF_DIR, HADOOP_USER_NAME, JAVA_HOME, JAVA_OPTS, LIBHDFS_OPTS, TZDIR, DORIS_LOG_TO_STDERR, and AWS credential providers (AWS_ROLE_ARN, AWS_WEB_IDENTITY_TOKEN_FILE, AWS_CONTAINER_CREDENTIALS_*). No password-via-env pattern — database passwords are never read from environment.| Knob | Default | Maintainer stance | Effect on model |
|---|---|---|---|
enable_ssl (FE MySQL/HTTP) | off | (Q7) Off IS supported production posture | §4.9 disclaims wire confidentiality unconditionally |
enable_ssl (Arrow Flight) | off | Same as above | Same |
enable_java_udf (FE) | on (maintainer, M10) | Intentional | §4.10 (4) “treat SUPER as RCE” is load-bearing in default |
enable_python_udf (FE) | on (maintainer, M10) | Intentional. Asymmetric with BE | FE allows registration; BE requires enable_python_udf_support to actually execute |
enable_python_udf_support (BE) | off (maintainer, M10) | Intentional. Operator must opt in to actually run Python UDFs | Default deployment cannot execute Python UDFs even if FE accepts them |
numFailedLogin (per-user, CREATE USER ... FAILED_LOGIN_ATTEMPTS N) | 0 / DISABLED (maintainer, M11) | (A) Off IS supported production posture; operator must enable per user | §4.10 (NEW) requires per-user enable for any account on a network-reachable client port |
passwordLockSeconds (per-user, ... PASSWORD_LOCK_TIME T) | 0 / DISABLED (maintainer, M11) | Same | Same |
enable_all_http_auth (FE, HTTP 8030) | on, not runtime-mutable (maintainer, M19) | On IS the supported production posture. Turning it off requires editing fe.conf and restarting — deliberately not an ADMIN SET command, so disabling authentication is a recorded on-disk decision. A migration aid for clusters upgrading from a release where it defaulted off, not a supported steady state | On: §4.8 (11) (authentication) applies unconditionally and a bypass is VALID; authorization is the separate, narrower §4.8 (12) with recorded gaps. Off: knob flipped toward the less-secure side → OUT-OF-MODEL: non-default-build. Note the effective value may come from fe_custom.conf, not fe.conf |
enable_all_http_auth (BE, webserver 8040) | off, not runtime-mutable (maintainer, M19) | Unchanged in this release — only the FE default was flipped. BE 8040 is a Zone-2 port (§4.4) that operators are already required to keep off end-user networks, so the compatibility cost of flipping it was judged to outweigh the gain. Changing it requires editing be.conf and restarting (DEFINE_Bool, not DEFINE_mBool) | Off: BE 8040 handlers declared with the NONE privilege type answer without credentials → BY-DESIGN: property-disclaimed (§4.9), not VALID |
auth_type | native | LDAP / Kerberos / OIDC are non-default backends | Out of this row's scope (handled in family row 4) |
Cluster shape: on-prem vs cloud/ | on-prem | Both shapes supported (maintainer, Q2) | Cloud adds Meta Service component (family row 3); cloud has additional tenant-boundary claim per §4.8 |
A vulnerability report of “I sniffed plaintext credentials on port 9030 in default config” is closed BY-DESIGN: property-disclaimed per Q7 → §4.9 / §4.10. A vulnerability report of “I brute-forced account analytics_user in default config (no FAILED_LOGIN_ATTEMPTS set)” is closed the same way per M11 → §4.9 / §4.10.
enable_all_http_auth now defaults on for FE (maintainer, M19). Prior releases shipped it off on both sides, so part of the FE HTTP surface — the metadata, statistics and admin REST endpoints, and the privilege check on part of the FE admin surface — answered without checking credentials or privileges. That default was a compatibility concession, not a security stance, and it has been flipped on FE 8030 only. The consequence for the model: unauthenticated access to those FE endpoints is no longer disclaimed; it is a violation of §4.8 (11) and reports of it are VALID. Two carve-outs: (a) FE /metrics on 8030 is public by design and the flag does not gate it — see §4.9; (b) BE 8040 is unchanged — its default stays off, and its NONE-privilege handlers remain disclaimed under §4.9. Do not assume the two ports behave alike.
Upgrade consequence, and what an operator turning it back off is buying. A cluster upgrading from a release where the flag defaulted off may have callers that poll those FE endpoints anonymously — monitoring agents, health probes, ops scripts, and any tooling driving the FE /api/** REST surface. They start receiving 401 on upgrade. Metrics scrapers pointed at FE /metrics or at BE 8040 are not affected, since neither is gated by the FE flag. The supported fix is to give those callers credentials (§4.10 (12)). An operator who instead sets enable_all_http_auth = false has flipped a §4.5a knob toward the less-secure side and is back to the pre-flip exposure: findings that require the flag off are then closed OUT-OF-MODEL: non-default-build, and the operator owns the risk.
Where the effective value comes from. FE reads fe.conf and then ${custom_config_dir}/fe_custom.conf, and values in the latter overwrite the former. In releases where this flag was mutable, ADMIN SET FRONTEND CONFIG (...) PROPERTIES("persist" = "true") wrote to fe_custom.conf; making the flag non-mutable in this release neither removes nor migrates such a value. An upgraded cluster can therefore have no false entry anywhere in fe.conf and still start with authentication off. “fe.conf says true” is not sufficient evidence that a cluster is running with the flag on — read the effective value back (/api/show_config, ADMIN SHOW FRONTEND CONFIG) and check fe_custom.conf. Operators upgrading should delete any stale entry from fe_custom.conf to pick up the new default; see §4.10.
Security-testing baseline. Security scans, penetration tests, fuzzing campaigns, and automated review agents MUST run against a cluster whose effective enable_all_http_auth is true on FE — i.e. do not turn it off for the test run, and confirm it is on (per the paragraph above, not by reading fe.conf alone) before reporting FE HTTP-surface coverage. On BE it defaults off; a test run may turn it on to probe BE 8040, but findings that require it to be on there are hardening observations, not defects. A run performed with the flag off does not constitute coverage of the HTTP surface: every finding it produces is OUT-OF-MODEL: non-default-build, and the findings that actually matter — endpoints that skip authentication or skip the caller's privilege check with the flag on — go unfound.
Per-endpoint trust table.
| Endpoint | Message / parameter | Trust | Caller / operator must enforce |
|---|---|---|---|
| FE MySQL 9030 | handshake bytes (pre-auth) | untrusted (maintainer, Q6) | nothing — Doris memory-safe by §4.8 (1) |
| FE MySQL 9030 | username / auth response | untrusted (maintainer, Q6) | server-side: brute-force resistance is not default; operator must CREATE USER ... FAILED_LOGIN_ATTEMPTS per §4.10 |
| FE MySQL 9030 | SQL text (post-auth) | untrusted (maintainer, Q5) | nothing — parser/planner memory-safe by §4.8 (2) |
| FE MySQL 9030 | SQL semantic content (table / column / privilege requested) | untrusted, RBAC-enforced (maintainer, Q5) | nothing — RBAC enforced by §4.8 (4) |
| FE MySQL 9030 | iceberg.rest.uri and similar URLs in CREATE EXTERNAL CATALOG | post-auth, attacker-controllable (maintainer, M13) | operator: only grant CREATE CATALOG privilege to admins; otherwise SSRF surface (§4.9) |
| FE HTTP 8030 | request bytes (pre-auth) | untrusted | memory safety |
| FE HTTP 8030 | request body (post-auth) | untrusted within RBAC | RBAC |
| FE HTTP 8030 | /api/show_proc, admin REST surface | post-auth, privileged | RBAC; admin-only endpoints must check. The privilege check on part of this surface is gated on enable_all_http_auth (maintainer, M19), on by default (§4.5a) — operator: do not turn it off |
| FE HTTP 8030 | metadata / statistic / import REST endpoints | post-auth (maintainer, M19) | nothing in default config — authenticated by §4.8 (11). Callers must present credentials |
FE HTTP 8030 /metrics | anonymous by design — NOT covered by enable_all_http_auth (code-verified, M19) | MetricsAction is deliberately public and is not routed through the FE auth path; the flag does not change it. Operator: keep 8030 off untrusted networks if FE metrics are sensitive | |
FE HTTP 8030 /api/health | anonymous by design — NOT covered by enable_all_http_auth (code-verified, M19) | HealthAction is deliberately public and the flag does not gate it. It discloses liveness plus total/online backend counts. Excluded from §4.8 (11); see §4.11a before filing it as a bypass | |
FE HTTP 8030 /api/get_small_file, /api/bootstrap | cluster token (+ cluster id) instead of a user password (code-verified, M19) | these are the FE endpoints that BE, the CDC client and a joining FE call with only the cluster token; the token is verified and is the credential, so enable_all_http_auth does not additionally demand a password on the token-bearing path. A leaked cluster token is a Zone-2 compromise (§4.5) | operator: treat the cluster token as a secret; do not expose 8030 to untrusted networks |
FE HTTP 8030 /api/streaming/commit_offset, /api/streaming/report_task_failure | cluster token only — no user credential is accepted at all (code-verified, M19) | StreamingJobAction.checkAuth requires a token header and verifies it against the cluster token; there is no password path. Same disposition as the row above: token absent or invalid → VALID; no user password while a valid token is presented → by design | |
FE HTTP 8030 /api/{db}/{table}/_stream_load | user password, or the cluster token on the token-bearing path (code-verified, M19) | the token branch is a credential in the same sense as the rows above; the password branch is covered by §4.8 (11) | |
| FE Arrow Flight 8070 | handshake | untrusted | memory safety |
| FE Arrow Flight 8070 | result-stream consumption | mostly post-auth | RBAC |
| BE Arrow Flight 8050 | handshake bytes (pre-auth) (maintainer, M7) | untrusted | memory safety |
| BE Arrow Flight 8050 | result-stream consumption (post-auth) | untrusted within RBAC | RBAC; results must respect querying user's grants |
| FE 9020 (RPC) | all parameters | trusted (Zone-2) (maintainer, Q1) | operator: network isolation |
| FE 9010 (edit log) | all parameters | trusted (Zone-2) | operator: network isolation |
| BE 8060 (BRPC) | all parameters | trusted (Zone-2) (maintainer, Q1) | operator: network isolation |
| BE 8040 (webserver) | all requests | trusted (Zone-2) | operator: do not expose to authenticated end-users (§4.11). enable_all_http_auth still defaults off here — only the FE default was flipped (maintainer, M19) — so handlers declared with the NONE privilege type answer without credentials in default config. Network isolation is the control |
| BE 9050 (heartbeat) | FE→BE control msgs | trusted (Zone-2) | operator: network isolation |
| BE 9060 (BE↔BE) | fragment exec, data transfer | trusted (Zone-2) | operator: network isolation |
| Broker (Thrift) | all parameters | trusted (Zone-2) | operator: network isolation |
| Cloud Meta Service ↔ tenants | per-tenant requests (maintainer, M2) | untrusted across the tenant boundary | Meta Service must enforce; cross-tenant leak/escalation is VALID |
| External catalog metadata (HMS, Iceberg manifests, JDBC driver responses) | Zone-3 admin-trusted (maintainer, Q8) | admin: do not connect untrusted catalogs | |
| External data files (Parquet/ORC/Avro/JSON/CSV from S3/HDFS/Azure) | Zone-3 admin-trusted (maintainer, Q8) | admin: do not point Doris at untrusted file systems | |
UDF code (Java JAR / C++ .so / Python script) | trusted (SUPER-installed) (maintainer, Q3, M3) | admin: only install code you wrote / audited | |
| JDBC driver JAR (loaded via JDBC catalog) | trusted (SUPER-attached) (maintainer, Q3, M3) | admin: only attach catalogs whose drivers you trust |
Size / shape / rate. Doris does not commit to bounded resource behavior on adversarial post-auth SQL (maintainer, Q5). Operator must use the §4.10 (3) knob set.
In-scope adversaries:
CREATE CATALOG privilege but no SUPER (maintainer, M13). Narrow SSRF actor: can attach an Iceberg REST catalog whose iceberg.rest.uri is an attacker-supplied URL, causing FE to issue HTTP requests to internal hosts. Mitigation is operator-side per §4.10.[cloud only] (maintainer, M2). Cross-tenant adversary: any leak / escalation across the Meta-Service-enforced tenant boundary is VALID.Out-of-scope adversaries:
| Adversary | Reason | Disposition |
|---|---|---|
| Cluster-internal network attacker | (Q1) Network isolation is operator's job | OUT-OF-MODEL: adversary-not-in-scope |
| Side-channel observer (timing, cache, branch-predictor) | (Q5) Not in model | OUT-OF-MODEL: adversary-not-in-scope |
SUPER / ADMIN_PRIV user behaving maliciously | (M3) admin trusted by definition | OUT-OF-MODEL: adversary-not-in-scope |
Co-tenant escape at K8s / OS level [cloud] | Meta Service tenant boundary IS in model (§4.8); host/K8s isolation is the cloud operator's job | OUT-OF-MODEL: adversary-not-in-scope for OS-level; VALID for Meta-Service-level |
| Eavesdropper on the wire when TLS off | (Q7) Default disclaims wire confidentiality | BY-DESIGN: property-disclaimed (§4.9) |
Brute-force attacker against an account without FAILED_LOGIN_ATTEMPTS set | (M11) Default disclaims; operator's job | BY-DESIGN: property-disclaimed (§4.9) |
| Compromised external catalog (Hive/Iceberg/JDBC/S3 source) | (Q8) admin-trusted | OUT-OF-MODEL: trusted-input |
| Operator misconfiguration (e.g., exposing 8060 to public internet) | (Q2) Not a supported deployment | OUT-OF-MODEL: adversary-not-in-scope |
| Byzantine FE follower / BE replica | (M6) honest peers assumed | OUT-OF-MODEL: adversary-not-in-scope |
For each: property + condition, violation symptom, severity tier, provenance.
Memory safety on untrusted MySQL handshake / auth bytes (FE, pre-auth) (maintainer, Q6). Violation symptom: FE JVM crash, OOB, info disclosure. Severity: security-critical.
Memory safety on untrusted SQL text (FE, post-auth) (maintainer, Q5). Violation symptom: FE crash, OOB, parser RCE. Severity: security-critical when reachable from a non-SUPER user.
Memory safety on untrusted HTTP request bytes (FE, pre- and post-auth) (maintainer, derived from Q5/Q6). Severity: security-critical.
Memory safety on untrusted BE Arrow Flight bytes (BE, pre- and post-auth) (maintainer, M7). Violation symptom: BE crash, OOB, parser RCE in Arrow Flight handler. Severity: security-critical.
RBAC enforcement: an authenticated user cannot read, modify, or discover existence of objects outside their grant scope (maintainer, Q5). Condition: RBAC configured. Violation symptom: privilege escalation; reading rows / tables / databases / metadata not granted. Severity: security-critical. Excluded: side-channel inference per §4.3 (4).
Authentication of MySQL / HTTP / FE Arrow Flight / BE Arrow Flight clients (when credentials are presented) (documented; configurable backends: native, LDAP, Kerberos, OIDC). Violation symptom: wrong credential authenticates; session hijack. Severity: security-critical.
Per-tenant isolation enforced inside the Cloud Meta Service (maintainer, M2) [cloud only]. Condition: cluster runs the cloud/ variant; tenant T₁ requests must not see tenant T₂ metadata or data. Violation symptom: cross-tenant metadata read, cross-tenant data read, cross-tenant privilege escalation. Severity: security-critical.
Cluster metadata replication safety under non-Byzantine FE peers (maintainer, M6). Violation symptom: FE replica metadata divergence, lost ACK'd writes, BDB JE log fork. Severity: correctness-critical; CVE only if reachable from a Zone-0 actor.
Tablet replication consistency under non-Byzantine BE peers and the documented replication protocol (maintainer, M6). Severity: correctness-critical.
Per-user pre-auth lockout mechanism (PASSWORD_LOCK_TIME) is available and works when configured (maintainer, M11). Condition: operator has run CREATE USER ... FAILED_LOGIN_ATTEMPTS N PASSWORD_LOCK_TIME T for the account in question. Violation symptom: configured lockout fails to take effect; counter resets unexpectedly; wraparound. Severity: security-critical when the configured behavior is broken (NOT when default is unconfigured — see §4.9).
HTTP authentication on the FE HTTP surface (maintainer, M19). Condition: default config — enable_all_http_auth ships on for FE (8030) (§4.5a). Scope:
/api/** and /rest/v2/** REST actions), which must establish a caller identity — valid user credentials, or one of the credential forms listed under Excluded below — before returning data or performing an action.Read the property title literally: this is a claim about authentication, not a blanket claim about authorization. The default flip made the FE HTTP surface demand a credential; it did not introduce a centralized privilege check. Authorization on FE HTTP is per-handler, and its coverage is uneven. Handlers that do run a privilege check (for example checkAdminAuth, or a per-object PrivPredicate.SHOW filter) are covered by property (12) below; the ones that do not are listed as known gaps there. Do not cite this property as evidence that a given FE endpoint enforces the caller's privileges — check the handler.
BE 8040 is not in this property. Its enable_all_http_auth default is unchanged (off), so its NONE-privilege handlers stay disclaimed under §4.9 and are governed by Zone-2 network isolation, not by this property.
Violation symptom: an in-scope endpoint answers a request that carries no credential of any accepted form, or accepts invalid credentials. Severity: security-critical. Reports of this shape are VALID.
Excluded from this property — this list is meant to be exhaustive; a path that belongs here and is missing is a defect in this document, not a finding:
/metrics, deliberately anonymous, not gated by the flag — see §4.9./api/health (HealthAction), deliberately anonymous and not gated by the flag either. It returns liveness plus total/online backend counts. A report that /api/health answers an unauthenticated request is BY-DESIGN: property-disclaimed, not a violation.enable_all_http_auth = false — a §4.5a knob flipped toward the less-secure side, closed OUT-OF-MODEL: non-default-build. Note that the effective value can come from fe_custom.conf, which is read after and overwrites fe.conf; see §4.5a./api/get_small_file; FE /api/bootstrap when cluster_id+token are presented; FE /api/streaming/commit_offset and /api/streaming/report_task_failure, which accept only a token header and no user credential at all; the token branch of /api/{db}/{table}/_stream_load; and the BE handlers that accept an auth token. A report that one of these serves a request without a user password, while presenting a valid cluster token, is BY-DESIGN: property-disclaimed. A report that one of them accepts an invalid or absent token is VALID — with one recorded exception: /api/bootstrap validates the pair only on the ready path, so while the FE is not ready any two non-empty strings are accepted and the caller learns “not ready” and nothing else. That branch is a known, deliberate asymmetry (§4.14), not a bypass of this property.Per-handler authorization on the FE HTTP surface, where the handler implements it (maintainer, M19). Condition: property (11) holds and the endpoint in question runs a privilege check. Violation symptom: a handler that performs a privilege check returns data, or performs an action, that the authenticated caller has no privilege for — for example a metadata listing that leaks objects the caller has no SHOW privilege on, or an admin action reachable without ADMIN_PRIV. Severity: security-critical. Reports of this shape are VALID.
Known gaps — password-only handlers, not yet covered by this property. These authenticate but perform no SQL-equivalent authorization. They are recorded here so that a report against them is triaged as a known, accepted gap rather than silently treated as covered; closing them is tracked in §4.14. This list is maintained by inspection and has been wrong before — treat it as the current best inventory, not as a proof of completeness. A password-only handler that is missing from it is a defect in this document, and the finding against the handler still stands.
/api/backends (BackendsAction) — any valid account can enumerate backend host/port/liveness. Intentional: the Flink/Spark connectors call it with an ordinary load account to discover backends before a stream load.POST /rest/v2/api/storage_policy (AddStoragePolicyAction) — any valid account can journal a global storage policy, whereas the SQL equivalent (CREATE POLICY) requires global ADMIN_PRIV. This is a privilege gap, not a design choice.GET /rest/v2/api/es_catalog/get_mapping and POST /rest/v2/api/es_catalog/search (ESCatalogAction) — any valid account can issue raw mapping/search requests through the catalog's server-side credentials with no SHOW/SELECT check.POST /rest/v2/api/import/file_review (ImportAction) — any valid account can make FE list and read a caller-supplied external location with no LOAD or ADMIN check (outbound request from FE).GET /rest/v2/api/cluster_overview (StatisticAction) — any valid account reads cluster-wide dbCount / tblCount / beCount / feCount / diskOccupancy / remainDisk.POST /api/query_schema/{ns}/{db} (StmtExecutionAction) — any valid account can dump the CREATE TABLE DDL of arbitrary tables by naming them in the submitted SQL. The mechanism is worth recording because it is not obvious: the handler plans the statement at ExplainLevel.ANALYZED_PLAN, and NereidsPlanner.planWithoutLock returns at that level before running the rewriter — while CheckPrivileges is a rewrite rule (Rewriter, RuleType.CHECK_PRIVILEGES). So the usual “Nereids checks privileges” assumption does not hold on this path. Unchanged by the default flip: this handler always required a credential and never checked privileges.Until these carry a privilege check, a report of “authenticated low-privilege user performed X here” against one of them is BY-DESIGN: property-disclaimed with this section cited, and should be filed against the §4.14 follow-up rather than closed as noise.
Resource properties — threshold: NONE. Doris explicitly makes no quantitative or categorical resource guarantee on a post-auth single-user query (maintainer, Q5). Operator must use the §4.10 (3) knob set.
State plainly:
numFailedLogin = 0 and passwordLockSeconds = 0 — accounts have no lockout unless the operator enables it via CREATE USER ... FAILED_LOGIN_ATTEMPTS N PASSWORD_LOCK_TIME T. See §4.10 for the obligation./metrics (code-verified, M19). MetricsAction on FE 8030 is public by design and is not gated by enable_all_http_auth; turning the flag on does not change it. Anyone who can reach 8030 can read FE metrics — cluster topology hints, query and load counters, JVM state. Operator: if FE metrics are sensitive, restrict 8030 at the network layer (§4.10 (1)).NONE privilege type (maintainer, M19). BE ships enable_all_http_auth = false; only the FE default was flipped. BE metrics, health, and some debug / metadata endpoints answer without credentials. BE 8040 is a Zone-2 port (§4.4) and §4.3 (2) already requires it to be unreachable from end users; network isolation is the control. An operator who wants it closed sets enable_all_http_auth = true in be.conf and restarts.enable_all_http_auth = false on FE (maintainer, M19). The FE flag ships on and FE HTTP authn/authz is a stated property in default config (§4.8 (11)). Turning it off restores the pre-flip behavior — the metadata, statistics and import REST endpoints, and the privilege check on part of the FE admin REST surface, stop checking credentials. Doris makes no security claim about a cluster running that way; see §4.5a and §4.10 (12).EXECUTE to non-admin = granting whatever the UDF can do. Note: Java UDF default-on (enable_java_udf=true) per M10.SUPER-privileged insider (maintainer, M3).BaseController.java) only honors Authorization header (Basic/Bearer) or PALO_SESSION_ID cookie; Doris does NOT trust X-Forwarded-User / X-User-Authenticated / similar upstream-proxy headers. Setting up such a pattern via reverse proxy is unsupported.False-friend properties — features that look security-relevant but are not:
md5() / sha1() SQL functions are NOT cryptographic primitives. Checksum / compatibility functions; not safe for password hashing, MAC construction, or collision-resistance.password() SQL function (MySQL-compat) is NOT a KDF. Exists for wire compatibility; do not use for app-side credential storage.AES_ENCRYPT / AES_DECRYPT / DES_ENCRYPT / DES_DECRYPT SQL functions are NOT a managed-key envelope (maintainer, M12). Key handling is the application's job; ECB-mode and IV-reuse pitfalls are not mitigated; DES is broken — provided for compatibility only.current_user() and audit log entries are NOT tamper-evident records (maintainer, M12). Operational logs, not legal evidence; queryable by anyone with BE filesystem access.Well-known attack classes left to the caller / operator:
CREATE EXTERNAL CATALOG ... PROPERTIES("iceberg.rest.uri" = "http://...") does not validate or block localhost / private IPs. Operator must restrict CREATE CATALOG privilege to admins (§4.10, §4.11).COPY INTO / OUTFILE exfiltration — write privileges to external locations are admin-trusted; granting LOAD_PRIV / EXPORT_PRIV to a low-priv user opens an exfiltration channel (§4.11).The operator MUST:
exec_mem_limit (per-query memory), Workload Group via CREATE WORKLOAD GROUP ... (recommended; per-user/ group memory + CPU + concurrency caps), and max_connections / max_connection_per_user (FE config; prevent connection exhaustion).SUPER (and equivalent) as equivalent to local code execution on every BE in the cluster (maintainer, Q3, M3). Anyone who can install a UDF, attach a JDBC catalog, or set arbitrary ADMIN SET CONFIG values can run arbitrary code on the BE process. Note: Java UDF is default-on per M10 — SUPER discipline is load-bearing in default config.NetworkPolicy / namespace isolation and node-level isolation for OS-layer defense (maintainer, M2).root credentials in BI tools or app configs.CREATE USER ... FAILED_LOGIN_ATTEMPTS N PASSWORD_LOCK_TIME T. Doris does NOT ship a default lockout. A reasonable starting value: FAILED_LOGIN_ATTEMPTS 5 PASSWORD_LOCK_TIME 300 (operator's judgment).CREATE CATALOG privilege to administrators (maintainer, M13). Granting it to a low-privilege user lets them issue HTTP requests from FE to attacker-chosen URLs (SSRF) via Iceberg REST catalog. If you must grant it more broadly, apply network egress controls at the FE host level.enable_all_http_auth on, and migrate HTTP callers onto credentials (maintainer, M19). It ships on; do not turn it off. When upgrading from a release where it defaulted off, the migration the operator owes: (a) enumerate everything that calls the FE 8030 /api/** and /rest/v2/** surface — monitoring and alerting agents, load tooling, health probes, Kubernetes liveness/readiness checks, internal ops scripts. FE /metrics and BE 8040 are not affected; scrapers pointed only at those need no change; (b) give each of them credentials (HTTP Basic) and a Doris user with only the privileges it needs; (c) verify in staging before upgrading production — anything still polling anonymously will start getting 401; (d) check fe_custom.conf, not only fe.conf. It is read after fe.conf and overwrites it, and an earlier release where this flag was mutable may have persisted enable_all_http_auth=false into it via ADMIN SET FRONTEND CONFIG ... persist=true. That value survives the upgrade, so the new default silently does not take effect. Delete the stale entry, then confirm the effective value with ADMIN SHOW FRONTEND CONFIG. The flag is not runtime-mutable: turning it off means editing fe.conf and restarting the node. That is deliberate (M19) — disabling authentication should be a recorded, on-disk decision, not a runtime command, so the running posture is always auditable from the config files. “The config files” is plural on purpose: audit fe.conf and fe_custom.conf. It also means an upgrade surprise cannot be papered over with ADMIN SET FRONTENDS CONFIG; if you must fall back, do it in the config file and treat it as a temporary migration aid, not a resting state — it re-opens the §4.9 exposure and puts the cluster outside §4.8 (11).EXECUTE on a UDF to a non-admin user without understanding UDF runs with full BE privileges.CREATE CATALOG to non-admin users (maintainer, M13). Opens an SSRF vector via Iceberg REST URL.md5() / sha1() / password() SQL functions for app credential hashing. See §4.9 false-friends.LOAD_PRIV / EXPORT_PRIV to low-privilege users. Exfiltration channel.cloud/ deployments without K8s NetworkPolicy / namespace isolation at the host layer. Meta Service enforces the tenant data boundary (§4.8 (7)), but K8s/host-level isolation is still the operator's job.FAILED_LOGIN_ATTEMPTS (maintainer, M11). Brute-forceable with no server-side lockout.enable_all_http_auth off to unbreak an anonymous monitoring agent or ops script after an upgrade, and leaving it off (maintainer, M19). It is a migration aid. The fix is to give the caller credentials; see §4.10 (12).enable_all_http_auth turned off (maintainer, M19). Every finding it produces is OUT-OF-MODEL: non-default-build, and the real bypasses — endpoints that skip authn/authz with the flag on — go unfound. See the security-testing baseline in §4.5a.Patterns scanners / fuzzers / AI analyzers / human reviewers repeatedly flag that are NOT bugs given this model. Internal primary; cite externally only when closing a specific report (maintainer, M18).
OUT-OF-MODEL: adversary-not-in-scope per §4.4.BY-DESIGN: property-disclaimed per §4.9 (Q7).analytics_user in default config (no FAILED_LOGIN_ATTEMPTS set).” — BY-DESIGN: property-disclaimed per §4.9 (M11); operator's obligation per §4.10 (10).SELECT * FROM huge_table CROSS JOIN huge_table causes BE OOM.” — BY-DESIGN: property-disclaimed per §4.9 (Q5); operator's obligation per §4.10 (3).md5() / sha1() are cryptographically broken.” — BY-DESIGN: property-disclaimed per §4.9 false-friends.DES_ENCRYPT is broken.” — Same.Runtime.exec().” — OUT-OF-MODEL: trusted-input per §4.6 (M3).OUT-OF-MODEL: trusted-input per §4.6 (Q8).use_untrusted_ssl().” — Configurable per-catalog; admin's choice. Tag the connection, not the call. OUT-OF-MODEL: trusted-input.OUT-OF-MODEL: adversary-not-in-scope per §4.7 (M6).mysql/mysql-9.x.x/ has an XYZ issue.” — OUT-OF-MODEL: unsupported-component per §4.2 row 9.samples/ / pytest/ / regression-test/ / task_executor_simulator/ has an XYZ issue.” — Per §4.2 row 10.fe_plugins/* (including auditloader) has an XYZ issue.” — OUT-OF-MODEL: unsupported-component per §4.2 row 11 (M4).extension/ / cdc_client/ has an XYZ issue.” — Per §4.2 row 12.ADMIN SET CONFIG ... allows arbitrary file path / arbitrary command.” — Requires ADMIN_PRIV; admin trusted by §4.7 (M3). OUT-OF-MODEL: adversary-not-in-scope.BY-DESIGN: property-disclaimed per §4.9 false-friends (M12)./metrics (port 8030) is readable without credentials.” — BY-DESIGN: property-disclaimed per §4.9 (M19). Public by design; not gated by enable_all_http_auth./api/health (port 8030) answers without credentials and discloses backend counts.” — BY-DESIGN: property-disclaimed per §4.8 (11) exclusion (b) (M19). HealthAction is deliberately public and the flag does not gate it; the response is liveness plus total/online backend counts. Excluded from property (11) explicitly, so this is not a bypass./api/streaming/commit_offset (or /api/streaming/report_task_failure) accepts a request with no user credential.” — BY-DESIGN: property-disclaimed per §4.8 (11) exclusion (d) (M19). These take a cluster-token token header and nothing else; the token is the credential. A report that they accept an absent or invalid token is VALID.BY-DESIGN: property-disclaimed per §4.8 (12) known gaps (M19), and file against the §4.14 follow-up. These handlers authenticate but do not authorize; that is a recorded open gap, not a violation of a property the project currently claims.BY-DESIGN: property-disclaimed per §4.9 (M19). The BE default is unchanged (off) and BE 8040 is a Zone-2 port; network isolation is the control. An operator may set enable_all_http_auth = true in be.conf to close it, but the default is not a defect.VALID per §4.8 (11) unless the reporter had turned the flag off, in which case it is OUT-OF-MODEL: non-default-build per §4.5a. Always confirm which config was tested before closing — ask for the effective enable_all_http_auth value on the tested cluster, i.e. the output of ADMIN SHOW FRONTEND CONFIG or /api/show_config, plus both fe.conf and fe_custom.conf. The flag is not runtime-mutable, but fe_custom.conf is read after fe.conf and overwrites it, so fe.conf alone is not authoritative (§4.5a).Per M17, model is updated only when a §4.12 trigger fires (no periodic review). Triggers:
numFailedLogin / passwordLockSeconds defaults change to non-zero (M11): §4.8 (5)/(10) re-stated as default property, §4.9 disclaimer drops, §4.11a entry drops.enable_java_udf default flips off (M10): §4.10 (4) becomes conditional on a §4.5a non-default knob.enable_all_http_auth FE default flips back to off (M19 inverted, e.g. if the upgrade breakage forces a revert): §4.8 (11) reverts to a conditional property, §4.9 re-states the unauthenticated-HTTP disclaimer unconditionally, §4.10 (12) becomes “turn it on” rather than “keep it on”, and the §4.11a entry inverts back to a default non-finding. (This trigger fired once already, in the on direction, on 2026-07-29 — see §4.14 wave 5.)enable_all_http_auth BE default flips on (M19 extended to BE 8040): §4.8 (11) extends to every HttpHandlerWithAuth handler, the §4.9 BE disclaimer and the §4.11a BE non-finding both drop.MODEL-GAP (§4.13). The correct response is to revise this model — add a §4.8 / §4.9 entry — not to make an ad-hoc call on the report.Closed set. Cite the section.
| Disposition | When | Licensed by |
|---|---|---|
VALID | Violates a §4.8 property via an in-scope §4.7 actor and §4.6 input. | §4.8, §4.6, §4.7 |
VALID-HARDENING | No §4.8 property violated, but the API enables a §4.11 misuse cleanly enough to warrant a hardening change. | §4.11 |
OUT-OF-MODEL: trusted-input | Requires attacker control of a §4.6 input marked trusted. | §4.6 |
OUT-OF-MODEL: adversary-not-in-scope | Requires a §4.7 capability that is excluded. | §4.7 |
OUT-OF-MODEL: unsupported-component | Lands in §4.2 rows 9–12. | §4.3 |
OUT-OF-MODEL: non-default-build | Only manifests when a §4.5a knob is flipped from its default toward the less-secure side. | §4.5a |
BY-DESIGN: property-disclaimed | Concerns a property §4.9 explicitly disclaims. | §4.9 |
KNOWN-NON-FINDING | Matches a §4.11a entry verbatim or closely. | §4.11a |
MODEL-GAP | Cannot be cleanly routed to any of the above. Triggers §4.12 — model gets revised before the report is closed. | (§4.12) |
Wave 3 — RESOLVED 2026-05-14. All 14 technical questions (M1–M14) answered by maintainer; promotions applied throughout the body. Summary table:
| ID | Topic | Outcome |
|---|---|---|
| M1 | Disclosure channel | security@apache.org (ASF) + short SECURITY.md linking back to this doc |
| M2 | Cloud tenancy | Shared Meta Service; per-tenant isolation IS a security claim (§4.8 new property, §4.7 new actor) |
| M3 | SUPER admin | Out-of-scope adversary by definition |
| M4 | auditloader | Stays out-of-model demo (row 11) |
| M5 | Resource knobs | exec_mem_limit + Workload Group + max_connections{,_per_user} |
| M6 | Byzantine peers | Honest peers assumed; out-of-scope adversary |
| M7 | BE Arrow Flight 8050 | Client-facing — Zone-0 (was Zone-2 in v0.1) |
| M8 | Toolchain | JDK 17 (FE), GCC 11+ libstdc++ (BE), Linux x86_64 + aarch64 |
| M9 | Negative claims | Subprocess: Python UDF + Python venv + Broker shell + CDC client; no FE custom signal handlers; env vars enumerated; no password-via-env |
| M10 | UDF defaults | enable_java_udf=true (FE), enable_python_udf=true (FE), enable_python_udf_support=false (BE); intentional asymmetric |
| M11 | Login lockout | No default lockout — operator's responsibility per §4.10 (10) |
| M12 | False friends | DES_*, Workload Group, Resource Tag, Audit Log added |
| M13 | SSRF | Real surface — Iceberg REST URL + non-admin CREATE CATALOG |
| M14 | Reverse-proxy auth | Code-verified NOT supported; no X-Forwarded-User trust |
Wave 4 — RESOLVED 2026-05-14. Process / meta:
| ID | Topic | Outcome |
|---|---|---|
| M15 | Versioning policy | Single living doc + model-version field at top, bumped per minor release |
| M16 | SECURITY.md coexistence | Short SECURITY.md at repo root linking back to this doc as canonical scope |
| M17 | Revision cadence | Trigger-driven only (§4.12 events); no periodic review |
| M18 | §4.11a publication | Internal primary; cite externally only when closing a specific report |
Wave 5 — RESOLVED 2026-07-29. HTTP surface:
| ID | Topic | Outcome |
|---|---|---|
| M19 | enable_all_http_auth (FE) | FE default flipped to true on 2026-07-29, and the flag is not runtime-mutable — it can only be changed on disk (fe.conf, or fe_custom.conf which overwrites it) with a restart, so the running posture is auditable from disk and cannot be silently dropped at runtime — but auditing it means reading both files, since a pre-flip release could have persisted false into fe_custom.conf (§4.5a). FE HTTP authentication is now a default-config property (§4.8 (11)); unauthenticated access to the FE 8030 /api/** and /rest/v2/** surface is VALID, not disclaimed. Authorization is a separate, narrower property (§4.8 (12)): the flip did not add a centralized privilege check, and AddStoragePolicyAction, ESCatalogAction and ImportAction remain password-only — a recorded open gap tracked in §4.14, not a claim this release makes. Carve-outs: FE /metrics and FE /api/health stay public by design and are not gated by the flag (§4.9, §4.8 (11) (b), code-verified); the cluster-token endpoints (including /api/streaming/*) authenticate by token, not password (§4.8 (11) (d)); and the BE default is unchanged (off) — BE 8040 stays governed by Zone-2 network isolation and its NONE-privilege handlers stay disclaimed (§4.9, §4.11a). Extending the flip to BE is tracked as a §4.12 trigger. Turning the FE flag off is a migration aid for upgrades (§4.10 (12)), lands findings in OUT-OF-MODEL: non-default-build (§4.5a), and is a misuse pattern as a resting state (§4.11) |
Open follow-up items (not blocking v1.0 acceptance):
model-version field to top of this doc per M15. Currently bound to commit 1d1846591f7 / pre-3.x release. Update when cutting next release.enable_all_http_auth default flip is a breaking change for anonymous callers of the FE /api/** and /rest/v2/** surface (health probes, ops scripts, management tooling) upgrading from an earlier release. Release notes and the upgrade guide must carry it, with the enable_all_http_auth = false fallback (in fe.conf, requiring a restart — the flag is not runtime-mutable) documented as temporary per §4.10 (12).AddStoragePolicyAction, ESCatalogAction, ImportAction, StatisticAction and StmtExecutionAction‘s query_schema authenticate but perform no SQL-equivalent authorization, so any valid account can respectively journal a global storage policy, query Elasticsearch through the catalog’s server-side credentials, make FE read a caller-supplied external location, read cluster-wide capacity statistics, and dump arbitrary table DDL. The default flip does not close these — it only means the caller must now hold some account. Adding the privilege checks (with negative low-privilege regression tests) is deliberately out of scope for the flip itself and is tracked here. Until then they are triaged per §4.8 (12), not as noise. The query_schema one deserves priority: it is a genuine read of another tenant's schema, and the reason it slips through — planning stops at ANALYZED_PLAN, before the rewrite-phase CheckPrivileges rule — may well apply to other callers of the planner that ask for an analyzed-only plan. That is worth a sweep, not just a point fix.BaseController.checkWithCookie‘s checkAuth flag gates two unrelated things at once: the global ADMIN_OR_NODE requirement and, in cloud mode, the overdue check. Handlers that pass false to do their own narrower authorization therefore also lose the fence, and must call checkInstanceOverdueIfCloud explicitly — the metadata controllers (MetaInfoAction, MetaInfoActionV2) now do. This is deliberately not folded into checkWithCookie: /api/query also passes false but hands the statement to a real JDBC session that enforces the overdue state itself and reports it as COMMON_ERROR; moving that rejection up would silently change the endpoint’s response code to UNAUTHORIZED. Anyone “simplifying” this back into checkWithCookie will break that contract — the overloaded flag is the underlying wart, and unpicking it properly is a follow-up./api/bootstrap accepts the cluster-id/token pair unverified while the FE is not ready. The pair is only validated on the ready path, so any caller supplying two non-empty strings can learn that a node is not ready; nothing else is disclosed on that branch. Validating earlier would mean comparing against getClusterId()/getToken() before the cluster is established and would turn “not ready” into “invalid cluster id” for a legitimately joining FE, so it was left alone here. If the not-ready branch ever grows a richer response, this must be revisited first.fe_custom.conf, not just fe.conf: a persisted enable_all_http_auth=false written by an earlier mutable release survives the upgrade and silently keeps authentication off (§4.5a).To be generated as docs/threat-model.yaml for automated / AI triage, encoding:
Not yet produced in v1.0. Optional follow-up.
(documented) / (maintainer) / (inferred). Zero (inferred) remaining. No hedge-tag variants.(inferred) resolved → no §4.14 wave-3 open items remain.v1.0 status: ACCEPTED for technical content; root SECURITY.md coexistence artifact complete per M16.