This is an automated email from the ASF dual-hosted git repository. rubenada pushed a commit to branch site in repository https://gitbox.apache.org/repos/asf/calcite.git
commit d8aced3bfb4b90cdf529e4ebc7c6a74c270a0266 Author: Vladimir Sitnikov <[email protected]> AuthorDate: Tue Jul 21 18:22:04 2026 +0300 [CALCITE-7605] Threat model: add Inputs, Downstream responsibilities, Triage dispositions Fold in the three additive sections proposed in vlsi/calcite#3, corrected against the code: - Inputs: map every attacker-controlled input to its governing rule. Add the metaTableFactory/metaColumnFactory PLUGIN properties, place operator under the RelJson row (SqlOperator loads only via RelJson), and note that fun selects built-in libraries rather than loading a class. - Downstream responsibilities: collect the host/operator duties in one place and drop the now-duplicated transport paragraph from the attacker section. - Triage dispositions: a closed outcome set a human or agent can route against. - Not a vulnerability: state that pushed-down SQL is by design, while a pushdown bug that reads beyond the configured schemas is P4. Also remove the draft-status line ahead of merge. Co-authored-by: Jarek Potiuk <[email protected]> Co-Authored-By: Claude Opus 4.8 <[email protected]> --- site/_docs/security_threat_model.md | 79 +++++++++++++++++++++++++++++++++---- 1 file changed, 72 insertions(+), 7 deletions(-) diff --git a/site/_docs/security_threat_model.md b/site/_docs/security_threat_model.md index 5f5deb7b9a..d9936197d4 100644 --- a/site/_docs/security_threat_model.md +++ b/site/_docs/security_threat_model.md @@ -31,8 +31,6 @@ contradicts this model is a feature request or a documentation gap, not a vulnerability. -**Status:** draft for PMC discussion; not yet ratified. - * TOC {:toc} @@ -58,11 +56,6 @@ ## Attacker and trust boundary points at. If a model references h2, h2's own settings and behavior are h2's concern, not Calcite's. -Because Calcite listens on no socket of its own, network transport, TLS, and -authentication belong to the host application, not to this model. A host that -lets an untrusted principal set connection properties has handed that principal -the attacker's full capability above. - ## Assets * the host running Calcite: no code execution, and no file access beyond @@ -70,6 +63,23 @@ ## Assets * the internal network reachable from that host: no attacker-directed outbound requests. +## Inputs + +Everything the attacker controls resolves to one of P1–P4 or to an explicit +carve-out below. A report that reaches a sink not covered here is a model gap +(see [Triage dispositions](#triage-dispositions)). + +| Input | How it is supplied | What it feeds | Governing rule | +| --- | --- | --- | --- | +| SQL text, including DDL | any statement on the connection | parser → validator → planner → generated code | P1–P4; parser nesting depth is a DoS surface (see [Denial of service](#denial-of-service)) | +| Class-naming connection properties — `schemaFactory`, `parserFactory`, `typeSystem`, `metaTableFactory`, `metaColumnFactory` | connection property or `model` | a class loaded through a Calcite SPI | [Surprising vs unsurprising class loading](#surprising-vs-unsurprising-class-loading) (P1) | +| `tableFactory` and function classes | `model` | a class loaded through a Calcite table or function SPI | Surprising vs unsurprising class loading (P1) | +| `dataSource`, `jdbcDriver` | connection property or `model` | a class loaded through a standard-Java SPI (`javax.sql.DataSource`, `java.sql.Driver`) | Surprising vs unsurprising class loading (P1); the host it then dials is P3 | +| `fun` | connection property | selects built-in function libraries by name | no class loading; ordinary SQL semantics under P1–P4 | +| `model` — inline JSON, a `file:` path, or a URL | connection property | schema/table factories and adapter operands | P1 (factories via SPI), P2 (local-file operands), P3 (a URL model, or a URL-fetching adapter) | +| A serialized RelNode plan (`RelJson`) — types and operators | any path that reconstructs a plan from attacker input | type and operator class resolution | Surprising vs unsurprising class loading (P1) | +| Adapter operands — e.g. a file/CSV/JSON path, or the os-adapter | `model` or SQL | the adapter's configured resource | P2 for a configured local path (opt-in ⇒ not a vulnerability); the os-adapter is opt-in (not a vulnerability) | + ## Security properties * **P1: no code execution.** Neither connecting nor running SQL may @@ -114,12 +124,39 @@ ## Not a vulnerability outside the attacker's reach by assumption. * The behavior of a third-party driver once Calcite has connected to the endpoint it was configured with. +* SQL that Calcite pushes down to a configured backend. Calcite generates the + text and sends it to the endpoint the operator configured, and the query + author can already reach that endpoint's data through the visible schemas. A + pushdown bug that reads beyond the configured schemas is P4 and a + vulnerability; the generated SQL reaching the configured backend is not. * Cross-tenant reads that follow from the embedder exposing more than one principal's schemas on a single connection. Calcite has no authentication or authorization; scoping each connection's root schema to what its principal may see is the embedder's job. P4 applies where the user submits only SQL; a user who also sets connection properties configures their own schema visibility. +## Downstream responsibilities + +Calcite is embedded, so several controls belong to the host or the operator, +not to the library. A finding that lands in one of these is not a Calcite +vulnerability. + +* **Transport and identity.** Calcite opens no socket. TLS, the network + perimeter, authentication, and authorization live in the host. A host that + lets an untrusted principal set connection properties hands that principal the + full capability in [Attacker and trust boundary](#attacker-and-trust-boundary). +* **Schema scoping.** Scope each connection's root schema to what its principal + may see; Calcite has no authentication or authorization. Cross-tenant reads + across schemas exposed on one connection are the embedder's to prevent (see + [Not a vulnerability](#not-a-vulnerability)). +* **Adapter selection.** Add the os-adapter and the file, CSV, or JSON adapters + only where the query author is trusted to reach what they expose. +* **Classpath.** The operator owns the classpath. Calcite gates class loading by + SPI; which classes are present is the operator's trust decision. +* **What a `model` points at.** A third-party driver or service a `model` + references is configured and patched by the operator; its behavior past the + connection boundary is out of this model. + ## Surprising vs unsurprising class loading Calcite loads a class named in a connection property or in SQL only to use it @@ -200,3 +237,31 @@ ## Denial of service Once the planning bounds exist, a single reasonably-sized query that exceeds them is a configuration choice, not a vulnerability. + +## Triage dispositions + +Every security report against Calcite resolves to exactly one of: + +* **Valid** — violates P1–P4, or matches an item in + [Always a vulnerability](#always-a-vulnerability). Gets a fix. A demonstrated + class-loading primitive qualifies on its own (see + [Triage rule for class-loading sinks](#triage-rule-for-class-loading-sinks)); + it need not be chained to end-to-end RCE. +* **Not a vulnerability (by design)** — matches an item in + [Not a vulnerability](#not-a-vulnerability): the os-adapter, an opt-in + file/CSV/JSON adapter reading its configured path, third-party driver or + pushed-down SQL behavior past the connection, or cross-tenant reads that + follow from the embedder's schema exposure. Close with a pointer to this + model. +* **Out of model** — requires a capability the attacker does not have (changing + a JVM system property or the classpath), or lands in a layer this model + assigns to the host (network transport, TLS, authentication, authorization). + Close; redirect to the operator or embedder. +* **Known limitation** — a [Denial of service](#denial-of-service) gap whose + control has not landed yet. Tracked as hardening, not a per-report + vulnerability, until the bound exists. +* **Duplicate** — the same sink or root cause is already tracked in an open + Jira. Link and close. +* **Model gap** — plausible, but this model does not clearly place it in or out. + Escalate to the PMC to decide, then update this document with the ruling so + the next report of its kind is no longer a gap.
