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.
- Project: Apache Doris (https://doris.apache.org)
- Model version binding: written against
masterat commit1d1846591f7, 2026-05-14. Per M15 (single-living-doc policy), themodel-versionfield 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). - Reporting cross-reference: per M1, security findings should be
reported to
security@apache.org(ASF security team will route to Doris). A shortSECURITY.mdat 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. - Status: v1.0 — technical model accepted. The four wave-4 (M15–M18)
meta/process answers are recorded below; the root
SECURITY.mdcoexistence artifact is complete, while model-version field policy text remains follow-up work. - Provenance legend:
- (documented) — stated in Doris' own README, code comments,
conf/*.conf, or user docs - (maintainer, Qn) / (maintainer, Mn) — answered by a Doris
committer in interviews on 2026-05-14.
Q1–Q8are wave-1/2 questions;M1–M18are wave-3/4 questions - (inferred) — producer's working hypothesis, not yet ratified. None remain in v1.0.
- (documented) — stated in Doris' own README, code comments,
- Draft confidence: 2 documented / 88 maintainer / 0 inferred. Up from v0.1 (2 / 45 / 37); all 14 wave-3 and 4 wave-4 questions resolved on 2026-05-14.
One-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):
- (A) On-prem / single-tenant — FE+BE+Broker processes inside a corporate network or private VPC. Cluster-internal network is implicitly trusted by operator-provided isolation. Default shape.
- (B) Cloud variant —
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 isVALID, notOUT-OF-MODEL.
Deployment shape explicitly OUT of scope (maintainer, Q2):
- Direct internet exposure of any Doris-listened port. Collapses §4.4 trust model.
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.
- Direct internet exposure of any port (maintainer, Q2).
Operators must place Doris behind a network perimeter (VPC,
firewall, K8s
NetworkPolicy, equivalent). - Cluster-internal-network adversary (maintainer, Q1). The trust boundary sits at the client-facing ports (§4.4). An attacker reaching BE BRPC 8060, BE Webserver 8040, FE Edit-log 9010, FE RPC 9020, BE Heartbeat 9050, BE↔BE 9060, or the FS broker is presumed to have already compromised the operator's network.
- DoS via pathological SQL or query plans (maintainer, Q5).
A single authenticated SQL user submitting an unbounded-resource
query is not a Doris bug. Operators must constrain users via
the canonical knob set (maintainer, M5):
exec_mem_limit(per-query memory cap), Workload Group (CREATE WORKLOAD GROUP ...— recommended production posture for memory/CPU/ concurrency caps per user/group), andmax_connections/max_connection_per_user(FE config, prevent connection exhaustion). - Side-channel / timing-based information disclosure (maintainer, Q5).
- Adversary-controlled external catalog data (maintainer, Q8).
Bytes returned from admin-connected Iceberg/Hive/Hudi/Paimon/
JDBC/S3 catalogs are trusted. Crashes from crafted Parquet/ORC/
Avro/JSON files are
OUT-OF-MODEL: trusted-input. SUPER-privileged adversary (maintainer, M3).SUPER(andADMIN_PRIV/ equivalent) holders are trusted by definition. RCE achievable only after acquiringSUPER— UDF install, JDBC driver attach, FE plugin registration,ADMIN SET CONFIG—OUT-OF-MODEL: adversary-not-in-scope.- Compromise of an external system Doris connects to. Downstream effects on Doris are out of model per (5).
- Transport-layer confidentiality on default config
(maintainer, Q7). TLS off by default IS the supported production
posture; "credentials sniffable in default config" is
BY-DESIGN: property-disclaimed(§4.9). - Default ship of pre-auth login lockout (maintainer, M11).
Doris ships
numFailedLogin = 0andpasswordLockSeconds = 0— the mechanism exists but is opt-in per user viaCREATE USER ... FAILED_LOGIN_ATTEMPTS N PASSWORD_LOCK_TIME T. "I brute-forced an account in default config" isBY-DESIGN: property-disclaimedplus an §4.10 obligation. - Byzantine cluster peers (maintainer, M6). BDB-JE FE replication and tablet replication assume honest peers.
- Co-tenant escape at the K8s / OS level (maintainer, M2 by extension). M2 commits to per-tenant isolation enforced inside the Meta Service; OS / K8s / hypervisor isolation between co-tenant pods is the cloud operator's job, not Doris'.
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):
- OS: Linux x86_64 and Linux aarch64 (both first-class).
- FE runtime: JDK 17.
- BE toolchain: GCC 11+ libstdc++ (or equivalent conformant C++ toolchain matching the official docker build image).
- Anything else (different JDK, non-conformant C++ toolchain) is
OUT-OF-MODEL: non-default-build.
Operational assumptions:
- Allocator: BE defaults to jemalloc.
- Concurrency: BE assumes a conformant C++ memory model with atomic intrinsics; FE assumes the JMM. Neither is signal-safe.
- Filesystem: BE assumes ownership of
storage_root_pathdirectories; concurrent external mutation is undefined. - Network: cluster-internal network is treated as a security boundary (operator's responsibility) (maintainer, Q1).
- Time: FE replica clock skew tolerated within Raft / BDB-JE bounds; clock-rollback is not an attacker capability.
Negative claims (what Doris does NOT do to its host) (maintainer, M9 — code-verified):
- BE process spawns subprocesses only in these cases: Python UDF
execution (
fork()), Python venv creation (system()), Broker shell utilities (popen()), and CDC client (fork()). No other arbitrary subprocess execution. - FE process does NOT install custom signal handlers beyond standard JVM behavior. Relies on JVM defaults.
- BE/FE consume the following environment variables at runtime:
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:
- Anonymous network attacker on a client-facing port (MySQL 9030, HTTP 8030, FE Arrow Flight 8070, BE Arrow Flight 8050). Capabilities: send arbitrary bytes, complete or abandon TLS handshake (when enabled), submit credential guesses without default lockout. Goals modeled: crash FE/BE; achieve RCE pre-auth; brute-force credentials (operator's job to enable per-user lockout per §4.10); enumerate users / cluster topology.
- Authenticated SQL user with restricted RBAC privileges. Capabilities: any SQL the protocol accepts, bounded only by the operator's workload-group config. Goals modeled: privilege escalation; reading objects outside grant; cross-user data leak via shared state; SQL execution layer escape (RCE); corrupting other users' data.
- Authenticated user with
CREATE CATALOGprivilege but noSUPER(maintainer, M13). Narrow SSRF actor: can attach an Iceberg REST catalog whoseiceberg.rest.uriis an attacker-supplied URL, causing FE to issue HTTP requests to internal hosts. Mitigation is operator-side per §4.10. - Authenticated user in tenant T₁ trying to reach tenant T₂
data
[cloud only](maintainer, M2). Cross-tenant adversary: any leak / escalation across the Meta-Service-enforced tenant boundary isVALID.
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-
SUPERuser. -
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 thecloud/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 Tfor 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_authships on for FE (8030) (§4.5a). Scope:- FE 8030 — every endpoint that routes through the FE auth
path (the
/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-objectPrivPredicate.SHOWfilter) 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_authdefault is unchanged (off), so itsNONE-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:
- (a) FE
/metrics, deliberately anonymous, not gated by the flag — see §4.9. - (b) FE
/api/health(HealthAction), deliberately anonymous and not gated by the flag either. It returns liveness plus total/online backend counts. A report that/api/healthanswers an unauthenticated request isBY-DESIGN: property-disclaimed, not a violation. - (c) Clusters where the operator has set
enable_all_http_auth = false— a §4.5a knob flipped toward the less-secure side, closedOUT-OF-MODEL: non-default-build. Note that the effective value can come fromfe_custom.conf, which is read after and overwritesfe.conf; see §4.5a. - (d) The cluster-token authenticated endpoints, where the
cluster token is the credential — authenticated, just not by
user password: FE
/api/get_small_file; FE/api/bootstrapwhencluster_id+tokenare presented; FE/api/streaming/commit_offsetand/api/streaming/report_task_failure, which accept only atokenheader 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, isBY-DESIGN: property-disclaimed. A report that one of them accepts an invalid or absent token isVALID— with one recorded exception:/api/bootstrapvalidates 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.
- FE 8030 — every endpoint that routes through the FE auth
path (the
-
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
SHOWprivilege on, or an admin action reachable withoutADMIN_PRIV. Severity: security-critical. Reports of this shape areVALID.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 globalADMIN_PRIV. This is a privilege gap, not a design choice.GET /rest/v2/api/es_catalog/get_mappingandPOST /rest/v2/api/es_catalog/search(ESCatalogAction) — any valid account can issue raw mapping/search requests through the catalog's server-side credentials with noSHOW/SELECTcheck.POST /rest/v2/api/import/file_review(ImportAction) — any valid account can make FE list and read a caller-supplied external location with noLOADorADMINcheck (outbound request from FE).GET /rest/v2/api/cluster_overview(StatisticAction) — any valid account reads cluster-widedbCount/tblCount/beCount/feCount/diskOccupancy/remainDisk.POST /api/query_schema/{ns}/{db}(StmtExecutionAction) — any valid account can dump theCREATE TABLEDDL 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 atExplainLevel.ANALYZED_PLAN, andNereidsPlanner.planWithoutLockreturns at that level before running the rewriter — whileCheckPrivilegesis 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-disclaimedwith 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:
- No transport-layer confidentiality by default. TLS off is the supported production posture (maintainer, Q7). Enable TLS on client ports if your network is not acceptably trusted, or layer mTLS / VPN externally.
- No default pre-auth brute-force defense (maintainer, M11).
Doris ships with
numFailedLogin = 0andpasswordLockSeconds = 0— accounts have no lockout unless the operator enables it viaCREATE USER ... FAILED_LOGIN_ATTEMPTS N PASSWORD_LOCK_TIME T. See §4.10 for the obligation. - No authentication on FE
/metrics(code-verified, M19).MetricsActionon FE 8030 is public by design and is not gated byenable_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)). - No authentication on the BE 8040 handlers declared with the
NONEprivilege type (maintainer, M19). BE shipsenable_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 setsenable_all_http_auth = trueinbe.confand restarts. - No HTTP API authentication once the operator sets
enable_all_http_auth = falseon 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). - No defense against query-DoS or query-OOM by an authenticated user (maintainer, Q5). Operator must use the §4.10 (3) knob set.
- No defense against malicious data files in connected external catalogs (maintainer, Q8).
- No sandboxing of UDF code (maintainer, Q3). Java/C++/Python
UDFs run with full BE process privileges; granting
EXECUTEto non-admin = granting whatever the UDF can do. Note: Java UDF default-on (enable_java_udf=true) per M10. - No defense against side-channel / timing attacks (maintainer, Q5).
- No Byzantine-fault tolerance (maintainer, M6).
- No defense against any actor inside the cluster network (maintainer, Q1).
- No defense against a
SUPER-privileged insider (maintainer, M3). - No mutual authentication on internal RPC. FE↔BE Thrift, BE↔BE BRPC, FE↔Follower, FE↔Broker accept any peer that can connect at the network layer.
- No reverse-proxy auth header support (code-verified, M14).
FE HTTP auth (
BaseController.java) only honorsAuthorizationheader (Basic/Bearer) orPALO_SESSION_IDcookie; Doris does NOT trustX-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_DECRYPTSQL 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.- The web UI (port 8030) is NOT a security boundary against an authenticated user. Anything the UI lets a user click, the user could already do via SQL.
- LDAP integration's local cache is NOT a backstop for LDAP compromise. If your LDAP server is owned, Doris auth is owned on the next refresh.
- Workload Group is NOT a security isolation boundary (maintainer, M12). It is resource isolation / QoS only. A query in workload group A operating on data accessible to workload group B is NOT a "security isolation" violation.
- Resource Tag (BE node tag) is NOT a tenant isolation boundary (maintainer, M12). It is a tablet scheduling hint, not "this user can only access this BE group" enforcement.
Well-known attack classes left to the caller / operator:
- SQL injection in applications building queries by string concatenation — application's job.
- Credential leakage in BI tools that store the Doris password in plaintext config — operator's job.
- Decompression / deserialization bombs in Parquet/ORC/Avro files — admin must trust the catalog source (§4.3 (5)).
- HTTP server-side request forgery (SSRF) via Iceberg REST
catalog URL (maintainer, M13) —
CREATE EXTERNAL CATALOG ... PROPERTIES("iceberg.rest.uri" = "http://...")does not validate or block localhost / private IPs. Operator must restrictCREATE CATALOGprivilege to admins (§4.10, §4.11). COPY INTO/OUTFILEexfiltration — write privileges to external locations are admin-trusted; grantingLOAD_PRIV/EXPORT_PRIVto a low-priv user opens an exfiltration channel (§4.11).- Account brute-force in default config — see §4.9 (no default lockout) and §4.10 (operator must enable per user).
The operator MUST:
- Place every Doris-listened port behind a network perimeter such that only client-facing ports (MySQL 9030, HTTP 8030, FE Arrow Flight 8070, BE Arrow Flight 8050) are reachable from authorized clients. Internal ports (§4.4) must be reachable only by other Doris processes in the same cluster. Failure collapses §4.4.
- Enable TLS on client-facing ports if the network is not acceptably trusted (maintainer, Q7).
- Configure resource caps per the canonical knob set
(maintainer, M5) before granting access to any user not fully
trusted:
exec_mem_limit(per-query memory), Workload Group viaCREATE WORKLOAD GROUP ...(recommended; per-user/ group memory + CPU + concurrency caps), andmax_connections/max_connection_per_user(FE config; prevent connection exhaustion). - Treat
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 arbitraryADMIN SET CONFIGvalues can run arbitrary code on the BE process. Note: Java UDF is default-on per M10 —SUPERdiscipline is load-bearing in default config. - Audit every external catalog before connecting it (maintainer, Q8).
- Audit every JDBC driver JAR before attaching a JDBC catalog that uses it.
- Deploy on a Linux host the operator controls.
- For cloud deployments, rely on the Meta Service's per-tenant
isolation (§4.8 (7)); additionally enforce K8s
NetworkPolicy/ namespace isolation and node-level isolation for OS-layer defense (maintainer, M2). - Rotate credentials on a schedule appropriate for the data;
do not embed
rootcredentials in BI tools or app configs. - Enable per-user pre-auth lockout for any account reachable
from a network-adjacent attacker (maintainer, M11):
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). - Restrict
CREATE CATALOGprivilege 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. - Keep
enable_all_http_authon, 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/metricsand 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) checkfe_custom.conf, not onlyfe.conf. It is read afterfe.confand overwrites it, and an earlier release where this flag was mutable may have persistedenable_all_http_auth=falseinto it viaADMIN 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 withADMIN SHOW FRONTEND CONFIG. The flag is not runtime-mutable: turning it off means editingfe.confand 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: auditfe.confandfe_custom.conf. It also means an upgrade surprise cannot be papered over withADMIN 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).
- Exposing BE webserver (8040) directly to authenticated end users. Default no auth; intra-cluster admin/metrics traffic only.
- Exposing BE BRPC (8060) outside the cluster network. Bypasses every Zone-0 access control.
- Exposing BE Arrow Flight 8050 without auth configured. It IS client-facing (M7) — auth must be configured if reachable.
- Granting
EXECUTEon a UDF to a non-admin user without understanding UDF runs with full BE privileges. - Connecting a JDBC catalog whose driver does eval-on-connection-string.
- Granting
CREATE CATALOGto non-admin users (maintainer, M13). Opens an SSRF vector via Iceberg REST URL. - Using
md5()/sha1()/password()SQL functions for app credential hashing. See §4.9 false-friends. - Granting
LOAD_PRIV/EXPORT_PRIVto low-privilege users. Exfiltration channel. - Treating Workload Group or Resource Tag as security isolation (maintainer, M12). They are not.
- Running
cloud/deployments without K8sNetworkPolicy/ 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. - Leaving accounts on a network-adjacent client port without
FAILED_LOGIN_ATTEMPTS(maintainer, M11). Brute-forceable with no server-side lockout. - Turning FE
enable_all_http_authoff 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). - Performing a security assessment of the FE HTTP surface with
enable_all_http_authturned off (maintainer, M19). Every finding it produces isOUT-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).
- "BE BRPC port 8060 has no authentication." —
OUT-OF-MODEL: adversary-not-in-scopeper §4.4. - "BE webserver port 8040 has no authentication." — Same.
- "BE↔BE port 9060 / heartbeat 9050 / FE Edit-log 9010 / FE RPC 9020 — no mutual TLS." — Same.
- "FS broker accepts unauthenticated Thrift calls." — Same.
- "MySQL credentials transmitted in plaintext on port 9030 in
default config." —
BY-DESIGN: property-disclaimedper §4.9 (Q7). - "Cluster traffic between FE and BE is unencrypted." — Same.
- "Brute-force possible against
analytics_userin default config (noFAILED_LOGIN_ATTEMPTSset)." —BY-DESIGN: property-disclaimedper §4.9 (M11); operator's obligation per §4.10 (10). - "
SELECT * FROM huge_table CROSS JOIN huge_tablecauses BE OOM." —BY-DESIGN: property-disclaimedper §4.9 (Q5); operator's obligation per §4.10 (3). - "
md5()/sha1()are cryptographically broken." —BY-DESIGN: property-disclaimedper §4.9 false-friends. - "
DES_ENCRYPTis broken." — Same. - "Java UDF runs without sandbox; can call
Runtime.exec()." —OUT-OF-MODEL: trusted-inputper §4.6 (M3). - "JDBC catalog driver runs arbitrary code on connection." — Same.
- "Reading a crafted Parquet from S3 crashes BE." —
OUT-OF-MODEL: trusted-inputper §4.6 (Q8). - "ES connector calls
use_untrusted_ssl()." — Configurable per-catalog; admin's choice. Tag the connection, not the call.OUT-OF-MODEL: trusted-input. - "FE follower can be tricked by a malicious peer to corrupt the
edit log." —
OUT-OF-MODEL: adversary-not-in-scopeper §4.7 (M6). - "
mysql/mysql-9.x.x/has an XYZ issue." —OUT-OF-MODEL: unsupported-componentper §4.2 row 9. - "
samples//pytest//regression-test//task_executor_simulator/has an XYZ issue." — Per §4.2 row 10. - "
fe_plugins/*(includingauditloader) has an XYZ issue." —OUT-OF-MODEL: unsupported-componentper §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." — RequiresADMIN_PRIV; admin trusted by §4.7 (M3).OUT-OF-MODEL: adversary-not-in-scope. - "Workload group / resource tag does not isolate cross-user
data." —
BY-DESIGN: property-disclaimedper §4.9 false-friends (M12). - "FE
/metrics(port 8030) is readable without credentials." —BY-DESIGN: property-disclaimedper §4.9 (M19). Public by design; not gated byenable_all_http_auth. - "FE
/api/health(port 8030) answers without credentials and discloses backend counts." —BY-DESIGN: property-disclaimedper §4.8 (11) exclusion (b) (M19).HealthActionis 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. - "FE
/api/streaming/commit_offset(or/api/streaming/report_task_failure) accepts a request with no user credential." —BY-DESIGN: property-disclaimedper §4.8 (11) exclusion (d) (M19). These take a cluster-tokentokenheader and nothing else; the token is the credential. A report that they accept an absent or invalid token isVALID. - "An authenticated low-privilege user could create a storage
policy / query Elasticsearch / make FE fetch an external URL over
HTTP." —
BY-DESIGN: property-disclaimedper §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. - "BE 8040 endpoint X answers an unauthenticated request." —
BY-DESIGN: property-disclaimedper §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 setenable_all_http_auth = trueinbe.confto close it, but the default is not a defect. - "FE 8030 endpoint X returns metadata to an unauthenticated
caller" (maintainer, M19) — not a non-finding by default.
The FE default is on, so this is
VALIDper §4.8 (11) unless the reporter had turned the flag off, in which case it isOUT-OF-MODEL: non-default-buildper §4.5a. Always confirm which config was tested before closing — ask for the effectiveenable_all_http_authvalue on the tested cluster, i.e. the output ofADMIN SHOW FRONTEND CONFIGor/api/show_config, plus bothfe.confandfe_custom.conf. The flag is not runtime-mutable, butfe_custom.confis read afterfe.confand overwrites it, sofe.confalone is not authoritative (§4.5a).
Per M17, model is updated only when a §4.12 trigger fires (no periodic review). Triggers:
- TLS default flips to on for any client port (Q7).
- Internal RPC gains mutual authentication or per-call auth (Q1 inverted).
- A new client-facing port is added (Zone-0 expands).
numFailedLogin/passwordLockSecondsdefaults change to non-zero (M11): §4.8 (5)/(10) re-stated as default property, §4.9 disclaimer drops, §4.11a entry drops.enable_java_udfdefault flips off (M10): §4.10 (4) becomes conditional on a §4.5a non-default knob.enable_all_http_authFE 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_authBE default flips on (M19 extended to BE 8040): §4.8 (11) extends to everyHttpHandlerWithAuthhandler, the §4.9 BE disclaimer and the §4.11a BE non-finding both drop.- Iceberg REST URL gains validation / localhost-blocking (M13): SSRF moves from §4.9 attack-class to §4.8 property; §4.11 misuse drops.
- A new catalog connector is added that touches data formats not previously parsed by BE (§4.6 Zone-3 surface grows).
- An entry in §4.2 rows 9–12 is promoted to "core supported".
- Cloud Meta Service tenant model changes (M2 inverted): if per-customer Meta Services replace the shared Meta Service, §4.8 (7) becomes a stricter property and §4.7 cross-tenant adversary moves to OUT-OF-MODEL.
- A vulnerability report routes to
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):
- Add
model-versionfield to top of this doc per M15. Currently bound to commit1d1846591f7/ pre-3.x release. Update when cutting next release. - Consider opening upstream issues per M10 (UDF default-off proposal), M11 (default lockout proposal), M13 (Iceberg URL validation). Each is a §4.12 trigger if accepted.
- Per M19, the FE
enable_all_http_authdefault 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 theenable_all_http_auth = falsefallback (infe.conf, requiring a restart — the flag is not runtime-mutable) documented as temporary per §4.10 (12). - Per M19, whether to extend the flip to BE 8040 is open. The BE default stays off in this change; the compatibility cost there is higher (metrics scrapers point at BE 8040) and BE 8040 is already required to be off end-user networks by §4.3 (2). Tracked as a §4.12 trigger.
- Per M19, the password-only FE handlers listed under §4.8 (12) are
an open gap:
AddStoragePolicyAction,ESCatalogAction,ImportAction,StatisticActionandStmtExecutionAction'squery_schemaauthenticate 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. Thequery_schemaone deserves priority: it is a genuine read of another tenant's schema, and the reason it slips through — planning stops atANALYZED_PLAN, before the rewrite-phaseCheckPrivilegesrule — 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. - Per M19, the cloud overdue-warehouse fence on FE HTTP is opt-in
per handler, not centralized.
BaseController.checkWithCookie'scheckAuthflag gates two unrelated things at once: the globalADMIN_OR_NODErequirement and, in cloud mode, the overdue check. Handlers that passfalseto do their own narrower authorization therefore also lose the fence, and must callcheckInstanceOverdueIfCloudexplicitly — the metadata controllers (MetaInfoAction,MetaInfoActionV2) now do. This is deliberately not folded intocheckWithCookie:/api/queryalso passesfalsebut hands the statement to a real JDBC session that enforces the overdue state itself and reports it asCOMMON_ERROR; moving that rejection up would silently change the endpoint's response code toUNAUTHORIZED. Anyone "simplifying" this back intocheckWithCookiewill break that contract — the overloaded flag is the underlying wart, and unpicking it properly is a follow-up. - Per M19,
/api/bootstrapaccepts 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 againstgetClusterId()/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. - Per M19, the upgrade guide must also tell operators to check
fe_custom.conf, not justfe.conf: a persistedenable_all_http_auth=falsewritten 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:
- Per-port trust zone (from §4.4)
- Per-endpoint parameter trust (from §4.6)
- Component-family in/out-of-scope (from §4.2 / §4.3)
- §4.5a knobs with default + maintainer stance
- §4.8 property → severity-tier + violation-symptom
- §4.9 disclaimed properties + false friends
- §4.11a known-non-findings (suppression-list shape; per M18 kept internal-primary)
- §4.13 disposition labels
Not yet produced in v1.0. Optional follow-up.
- Every section is substantive or marked N/A.
- No bullet would be more at home in a code review.
- No bullet restates README — README has no security content.
- Every claim carries
(documented)/(maintainer)/(inferred). Zero(inferred)remaining. No hedge-tag variants. - Header reports a draft-confidence count.
- All
(inferred)resolved → no §4.14 wave-3 open items remain. - Component families with distinct trust profiles modeled separately (FE / BE / cloud / brokers / catalogs / UDF code paths).
- §4.5a enumerates security-relevant knobs; both insecure-default cases (TLS per Q7, lockout per M11) explicitly resolved.
- §4.9 and §4.10 substantive; §4.9 names false-friends and well-known attack classes (now including SSRF per M13).
- §4.6 contains a per-parameter / per-endpoint trust table; BE Arrow Flight 8050 added per M7.
- §4.8 properties carry violation symptom + severity tier.
- Resource thresholds: §4.8 says "NONE — no commitment" per Q5. That is the threshold.
- §4.11a populated; M18 publication policy stated inline.
- §4.13 enumerates dispositions citing the section that licenses each.
- A reader can answer "what threats has Doris taken responsibility for, and which are left to me?".
- A triager can route an arbitrary finding to exactly one §4.13 disposition.
- Document length: ~7 pages (within recommended 3–8). v0.1's §4.14 wave-3 collapsed into a 14-row summary table.
v1.0 status: ACCEPTED for technical content; root SECURITY.md
coexistence artifact complete per M16.