| <!-- |
| Licensed to the Apache Software Foundation (ASF) under one or more |
| contributor license agreements. See the NOTICE file distributed with |
| this work for additional information regarding copyright ownership. |
| The ASF licenses this file to you under the Apache License, Version 2.0 |
| (the "License"); you may not use this file except in compliance with |
| the License. You may obtain a copy of the License at |
| |
| http://www.apache.org/licenses/LICENSE-2.0 |
| |
| Unless required by applicable law or agreed to in writing, software |
| distributed under the License is distributed on an "AS IS" BASIS, |
| WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| See the License for the specific language governing permissions and |
| limitations under the License. |
| --> |
| |
| # Apache Zeppelin — Security Threat Model |
| |
| ## §1 Header |
| |
| - **Project:** Apache Zeppelin |
| - **Modeled against:** `master` HEAD as of 2026-06-05 (latest released docs line). |
| - **Authors:** ASF Security team (v0 draft, generated via the |
| `threat-model-producer` rubric), for the Apache Zeppelin PMC to review. |
| - **Status:** **v0 — PMC-reviewed.** The Apache Zeppelin PMC has reviewed the |
| framing (confirmed) and answered the §14 questions; the answers are recorded |
| inline in §14 and folded into the sections below, with confirmed claims |
| re-tagged *(maintainer)*. |
| - **Version binding:** this model is versioned with the project. A report |
| against Zeppelin release *N* is triaged against the model as it stood at *N*. |
| - **Reporting cross-reference:** findings that violate a §8 property should be |
| reported privately per the project's disclosure channel |
| (`security@apache.org`); findings that fall under §3 or §9 are closed citing |
| this document. |
| - **Provenance legend:** *(documented)* = stated in Zeppelin's own docs/site; |
| *(maintainer)* = confirmed by a Zeppelin PMC member; *(inferred)* = reasoned |
| from code/docs/domain knowledge, not yet confirmed (each has a §14 question). |
| - **Confidence:** ~18 documented; the §14 answers fold the bulk of the former |
| *(inferred)* claims to *(maintainer)*; a few loose environmental assumptions |
| remain *(inferred)*. |
| |
| **What Zeppelin is.** Apache Zeppelin is a web-based, multi-user notebook |
| server for interactive data analytics. Users open notebooks in a browser and |
| run "paragraphs" of code against pluggable *interpreters* (Spark, Flink, |
| Python, JDBC, shell, etc.); the Zeppelin server launches and talks to |
| interpreter processes over a Thrift IPC channel and returns results to the |
| browser over a websocket. **Executing user-supplied code on the server is the |
| product's primary function, not a vulnerability** — the security model is |
| about *who is allowed to reach that capability and with what isolation*, not |
| about preventing code execution. |
| |
| ## §2 Scope and intended use |
| |
| - **Primary intended use** *(inferred)*: an operator-deployed, multi-tenant |
| analytics notebook server, run inside an organization's trusted network and |
| fronted by authentication, where authorized analysts author and run |
| notebooks against backend compute (Spark/Flink/etc.). |
| - **Deployment shape** *(documented)*: a long-running JVM server |
| (`zeppelin-server`) plus one or more interpreter processes; reached via HTTP |
| + websocket, optionally behind a reverse proxy (NGINX). |
| - **Caller roles** (a network service, so the role splits): |
| - **client / notebook user** — untrusted until authenticated; once |
| authenticated, trusted only up to their notebook/role permissions. |
| - **operator / admin** — trusted for the instance; owns `shiro.ini`, |
| interpreter settings, `zeppelin-site.xml`, the host. |
| - **anonymous visitor** — present **by default** (see §5a); trusted at |
| whatever level the deployment's authorization grants anonymous, which by |
| default is full access. |
| |
| **Component-family table** *(maintainer — §14.8)*: |
| |
| | Family | Entry point | Touches outside process? | In model? | |
| | --- | --- | --- | --- | |
| | Web/REST/websocket server | `org.apache.zeppelin.rest.*`, websocket | network | **yes** | |
| | AuthN/AuthZ (Shiro + notebook ACL + URL ACL) | `shiro.ini`, `NotebookAuthorization`, `SecurityRestApi` | filesystem (config) | **yes** | |
| | Interpreter launch + IPC | Thrift `RemoteInterpreterServer`, process launcher | child processes, network | **yes** (the launch/isolation boundary) | |
| | Interpreter-executed user code | `%spark`, `%sh`, `%python`, `%jdbc`, … | arbitrary (by design) | **boundary only** — the *code* is by-design; reaching/isolating it is in model | |
| | Credentials / datasource auth | `CredentialRestApi`, credential injection | filesystem, backends | **yes** | |
| | Notebook storage / repos | `NotebookRepo` (local FS, S3, Git, etc.) | filesystem / cloud | **yes** | |
| | Bundled interpreters / examples / web UI assets | `*-interpreter` modules, demos | varies | **all bundled interpreters first-class** for security purposes (§14.8); demo/example notebooks are a separate category | |
| |
| ## §3 Out of scope (explicit non-goals) |
| |
| - **Sandboxing the code a permitted user runs.** A user with run permission on |
| a notebook can execute arbitrary code (`%sh`, Spark driver code, etc.) by |
| design; Zeppelin does not attempt to confine what that code does on the host |
| or backend. *(maintainer — §14.3)* |
| - **Defending a deployment that disables authentication and is exposed to an |
| untrusted network.** The docs direct operators to enable Shiro *or* deploy |
| only in a secured/trusted environment *(documented)*; an unauthenticated, |
| internet-exposed instance is an operator misconfiguration, not a Zeppelin |
| defect (pending the §5a/§14 ruling on whether anonymous is a supported |
| posture). |
| - **Security of third-party interpreter backends** (the Spark cluster, the |
| JDBC database, the host shell) — Zeppelin brokers access; it does not own |
| those systems' security. *(inferred)* |
| - **Bundled demo / example notebooks** — a separate category from the |
| interpreters, threat-modeled separately if at all; integrators should not |
| extend core guarantees to them. (All bundled *interpreters* are first-class; |
| see §2 and §14.8.) *(maintainer — §14.8)* |
| |
| ## §4 Trust boundaries and data flow |
| |
| The **primary trust boundary is the authentication + authorization layer** |
| (Shiro realm → notebook ACL → URL ACL), not the API surface itself. Data flow |
| and the trust transitions it crosses: |
| |
| 1. Browser → **HTTP/websocket** → server: crosses the network boundary. |
| Untrusted until Shiro authenticates the session. *(documented)* |
| 2. Authenticated session → **notebook operation** (read/write/run): crosses |
| the notebook-ACL boundary (owner/reader/writer/runner). *(documented)* |
| 3. Run request → **interpreter process** over Thrift IPC: the server hands |
| user code to an interpreter. Whether this crosses an OS-user boundary |
| depends on **impersonation** (off by default → runs as the *server* OS |
| user). *(documented)* |
| 4. Interpreter → backend (Spark/JDBC/FS/shell): leaves Zeppelin's boundary |
| entirely. *(inferred)* |
| |
| **Reachability preconditions per family** (the triager's first test): |
| - A finding in the web/REST/websocket family is in-model only if reachable by |
| a network client **before** the Shiro auth gate, or by an authenticated user |
| **beyond** their granted role/notebook permission. |
| - A finding in interpreter-launch/IPC is in-model only if it lets a user cross |
| a boundary the model claims (e.g., one tenant reaching another tenant's |
| interpreter/credentials, or escaping the impersonation user when impersonation |
| is on). |
| - A finding that is "authenticated run-capable user executes code / reads files |
| as the interpreter's OS user" is **out of model** (that is the granted |
| capability) unless it crosses into another tenant or the operator boundary. |
| |
| ## §5 Assumptions about the environment |
| |
| - **Operator-controlled host and config** *(inferred)*: `shiro.ini`, |
| `zeppelin-site.xml`, credential stores, and the interpreter settings are |
| trusted inputs written by the operator, not attacker-controllable. |
| - **Network placement** *(documented)*: Zeppelin expects to sit in a secured/ |
| trusted network or behind an authenticating proxy; HTTPS is "highly |
| recommended" for the web/websocket channel. |
| - **Backend trust** *(inferred)*: the Spark/Flink/JDBC/SSH backends an |
| interpreter reaches are provisioned by the operator. |
| - **What the server does to its host** *(inferred — §14)*: launches child |
| interpreter processes; reads config + notebook storage; opens listening |
| sockets (HTTP/websocket, Thrift); with impersonation, performs SSH/`setuid`- |
| style user switching. It is *not* expected to run as root. |
| |
| ## §5a Build-time and configuration variants (the security-envelope knobs) |
| |
| This is the heart of Zeppelin's model — several **defaults are the less-secure |
| value**, so the model is ambiguous until the PMC rules on each (see §14 wave 1): |
| |
| | Knob | Default | Effect on model | Maintainer stance | |
| | --- | --- | --- | --- | |
| | Shiro authentication (`conf/shiro.ini`) | **absent → anonymous** *(documented)* | No auth boundary at all; every §8 authn/authz property is void | **dev-convenience** *(maintainer — §14.1)*: anonymous is *not* the supported posture; reports against an exposed anonymous instance are `OUT-OF-MODEL: non-default-build` | |
| | `zeppelin.notebook.public` / `ZEPPELIN_NOTEBOOK_PUBLIC` | **`true` → new notes public** *(documented)* | Empty-ACL note is readable/runnable by any authenticated (or anonymous) user | **by-design** *(maintainer — §14.2)*: public-by-default is intended; an empty-ACL note being readable/runnable is not a bug | |
| | Interpreter user impersonation | **off → runs as server OS user** *(documented)* | Without it, every run-capable user's code shares the *server's* OS identity/privileges and filesystem | **by-design** *(maintainer — §14.3)*: running as the server OS user is the documented default; OS isolation requires enabling impersonation | |
| | Interpreter binding mode (shared / scoped / isolated) | **shared** *(maintainer — §14.4)* | Process-level separation between users/notes; "isolated" is a *stability/resource* boundary, **not** a security sandbox | **maintainer — §14.4**: default is `shared`; no binding mode is a security sandbox | |
| | URL ACLs (`[urls]` in shiro.ini) gating `/interpreter`, `/credential`, `/configurations` | **not restricted unless operator adds them** *(documented)* | Sensitive admin endpoints open to any authenticated role absent explicit `[urls]` rules | **maintainer — §14.5**: no built-in admin gate; protection relies entirely on `shiro.ini [urls]` | |
| | HTTPS / security headers (`http_security_headers`) | **off/plain unless configured** *(documented)* | Credentials + session over plaintext; missing CSP/XFO | operator responsibility (§10); no CSP and Origin-based CSRF only — `VALID-HARDENING` *(maintainer — §14.10)* | |
| |
| **Insecure-default ruling (recorded).** The PMC has ruled that every insecure |
| §5a default above is a *dev-convenience / by-design* choice, not the supported |
| production posture: Zeppelin's stance is "open by default, secure by |
| configuration" (enable Shiro, or deploy only in a secured/trusted network). A |
| report that only manifests under one of these defaults is therefore |
| `OUT-OF-MODEL: non-default-build` (or `BY-DESIGN`), with the requirement living |
| in §10. See §14 wave 1 for the per-knob answers. |
| |
| ## §6 Assumptions about inputs |
| |
| Inputs and their trust (network-service shape — rows are endpoints/messages): |
| |
| | Surface | Input | Attacker-controllable? | Caller/operator must enforce | |
| | --- | --- | --- | --- | |
| | `POST` login / Shiro filter | credentials | **yes** (pre-auth) | strong realm config; lockout/rate-limit at proxy *(inferred)* | |
| | Websocket ops (run/edit/move paragraph) | notebook + paragraph payload | **yes** (authenticated user) | notebook ACL + run permission enforced server-side *(documented)* | |
| | `NotebookRestApi` / `InterpreterRestApi` | note id, interpreter settings | **yes** (authenticated user) | URL ACL + ownership checks, enforced server-side *(maintainer — §14.6)* | |
| | `CredentialRestApi` | per-user credentials | **yes** (authenticated user) | per-user credential isolation *(maintainer — §14.7)* | |
| | Paragraph code body | arbitrary code | **yes — by design** | this is the granted capability, not validated input | |
| | `shiro.ini`, `zeppelin-site.xml`, interpreter JSON | config | **no — operator-trusted** | filesystem perms on config/secret files *(inferred)* | |
| | Notebook storage backend contents | persisted notes | **mostly trusted** (written via the app) | integrity of the repo (S3/Git/FS) *(inferred)* | |
| |
| Size/shape/rate: *(maintainer — §14.9)* there is no rate limit and no |
| concurrent-interpreter-launch cap today; the PMC treats this as |
| `VALID-HARDENING` and welcomes the scan surfacing concrete limits. |
| |
| ## §7 Adversary model |
| |
| **In scope:** |
| - **Unauthenticated network client** (when Shiro is enabled): tries to reach |
| any authenticated capability without valid credentials — bypass the login |
| filter, forge/steal a session, reach a websocket/REST op pre-auth. |
| - **Authenticated lower-privileged user**: a legitimate user trying to exceed |
| their grant — read/edit/run another user's note they lack ACL for, read |
| another user's credentials, reach admin endpoints (`/interpreter`, |
| `/credential`) their role shouldn't, or (impersonation on) break out of their |
| impersonation identity into another user's or the server's. |
| |
| **Capabilities:** can send arbitrary HTTP/websocket traffic; can author |
| arbitrary code in paragraphs they may run; cannot (assumed) read the operator's |
| config/secret files or the host outside what their interpreter identity grants. |
| |
| **Explicitly out of scope:** |
| - The **operator/admin** and anyone with write access to `shiro.ini` / |
| interpreter config / the host — they have already won. |
| - A user **executing code within their own granted run permission** — that is |
| the product working as designed, even though the code can be `%sh rm -rf`. |
| - Anyone reaching a **default anonymous** instance over an untrusted network — |
| out of model pending the §5a/§14 ruling. |
| |
| ## §8 Security properties the project provides |
| |
| Each conditional on the relevant §5a knob being set securely. The PMC has |
| confirmed properties 1–5 below as committed properties (§14.5–§14.7), now |
| tagged *(maintainer)*; property 6 (resource/availability) is **not** a committed |
| property today (§14.9). |
| |
| 1. **Authentication of the web/REST/websocket surface** *when Shiro is |
| configured*. Violation symptom: an unauthenticated client performs an |
| operation requiring a session. Severity: **critical**. *(maintainer — |
| §14.6)* |
| 2. **Authorization of notebook operations per the owner/reader/writer/runner |
| ACL** *when auth is on*. Violation symptom: a user reads/edits/runs a note |
| they lack permission for. Severity: **critical**. *(maintainer — §14.6: |
| enforced server-side for every websocket/REST op, not client-side only)* |
| 3. **URL-level access control** for sensitive endpoints via `[urls]`. |
| Violation symptom: a non-admin reaches `/interpreter`, `/credential`, or |
| `/configurations` despite a restricting rule. Severity: **high**. |
| *(documented mechanism; maintainer — §14.5: no built-in admin gate, so this |
| property holds only when the operator adds `[urls]` rules)* |
| 4. **Per-user credential isolation** (one user cannot read another's injected |
| datasource credentials). Violation symptom: cross-user credential read. |
| Severity: **critical**. *(maintainer — §14.7)* |
| 5. **Impersonation confinement** *when enabled*: interpreter code runs as the |
| logged-in user, not the server user, and not as another user. Violation |
| symptom: code runs as a different identity than the session's. Severity: |
| **high**. *(maintainer — §14.3)* |
| 6. **Resource/availability** — **not a committed property today** *(maintainer — |
| §14.9)*. There is no rate limit or concurrent-launch cap. The PMC treats |
| hardening here as `VALID-HARDENING` and welcomes concrete recommendations |
| from the scan rather than suppressing them. |
| |
| ## §9 Security properties the project does *not* provide |
| |
| - **No sandbox of permitted code.** A run-capable user's paragraph executes |
| with the full authority of the interpreter's OS identity (the *server* user |
| unless impersonation is on). "Zeppelin runs my shell command" is not a |
| vulnerability. *(inferred — §14.3)* |
| - **No protection in anonymous/default mode.** With no `shiro.ini`, there is no |
| authn/authz boundary; everything in §8 is void. *(documented)* |
| - **No transport security by default.** Plaintext HTTP/websocket unless the |
| operator configures TLS; credentials transit in the clear otherwise. |
| *(documented)* |
| |
| **False-friend properties (call out explicitly):** |
| - **Interpreter "isolated" binding mode is not a security sandbox.** It gives |
| each user/note a separate interpreter *process* for stability and resource |
| separation; it does **not** confine what the code in that process can do to |
| the host or to shared backends, and absent impersonation all those processes |
| still run as the **same server OS user**. *(maintainer — §14.4)* |
| - **Notebook permissions are an application-layer ACL, not OS isolation.** A |
| user denied *read* on a note in the UI may still reach data through an |
| interpreter they *can* run if backends aren't separately access-controlled. |
| *(maintainer)* |
| |
| **Well-known attack classes left to the operator/integrator:** SSRF from |
| interpreter code reaching internal services; secrets-in-notebooks; XSS/CSRF on |
| the notebook web UI — *(maintainer — §14.10)* there is **no Content-Security- |
| Policy** and CSRF protection is **Origin-header-based only**, so strengthening |
| these (CSP, stronger CSRF) is welcome `VALID-HARDENING`; websocket cross-origin. |
| The point is to put integrators on notice. |
| |
| ## §10 Downstream / operator responsibilities |
| |
| For Zeppelin the "user" is the **operator** deploying it: |
| - **Enable Shiro authentication** (or keep Zeppelin strictly inside a trusted, |
| network-isolated perimeter). *(documented)* |
| - **Add `[urls]` rules** restricting `/interpreter`, `/credential`, |
| `/configurations` (and other admin paths) to admin roles. *(documented)* |
| - **Set `zeppelin.notebook.public=false`** if notebooks should default to |
| private. *(documented)* |
| - **Enable interpreter impersonation** for genuine multi-tenant isolation; do |
| not rely on binding mode alone. *(documented)* |
| - **Terminate TLS** and enable `http_security_headers`. *(documented)* |
| - **Protect `shiro.ini`, credential stores, and notebook storage** with host |
| filesystem permissions; do not run the server as root. *(inferred)* |
| - **Treat backends (Spark/JDBC/SSH) as reachable by any run-capable user** and |
| access-control them independently. *(inferred)* |
| |
| ## §11 Known misuse patterns |
| |
| - Exposing a **default (anonymous) Zeppelin to the public internet** — turns |
| the by-design code-execution surface into unauthenticated RCE-equivalent. |
| - Relying on **notebook ACLs while interpreters run shared/as-server-user**, so |
| a run-capable user reaches data the ACL meant to hide. |
| - Treating **"isolated" binding as a security boundary** between tenants. |
| - Storing **long-lived secrets in notebook source** instead of the credential |
| store, then sharing the note. |
| - Leaving **`/interpreter` and `/credential` reachable** by all authenticated |
| users (no `[urls]` rules). |
| |
| ## §11a Known non-findings (recurring false positives) |
| |
| The highest-leverage section for keeping scan output signal-heavy: |
| |
| - **"`%sh` / interpreter executes arbitrary shell or driver code → RCE."** |
| By design for a run-capable user; `OUT-OF-MODEL` / `BY-DESIGN` unless it |
| crosses a tenant or the operator boundary. (§3, §9) *(maintainer — §14.3)* |
| - **"Interpreter process runs as the Zeppelin server OS user / can read server |
| files."** Documented default behavior without impersonation; operator config, |
| not a defect. (§5a, §10) *(documented; maintainer — §14.3)* |
| - **"Anonymous user can do X"** reported against a deployment with **no |
| `shiro.ini`.** Out of model — auth is operator-enabled. (§5a, §9) |
| *(maintainer — §14.1)* |
| - **"No TLS / credentials in plaintext"** against a deployment the operator did |
| not configure for HTTPS. Operator responsibility. (§10) *(documented)* |
| - **Static-analysis "command injection / code execution" hits on the |
| interpreter execution path.** That path *is* the feature; in-model only if it |
| bypasses the authn/authz gate. (§4 reachability test) *(maintainer)* |
| |
| ## §12 Conditions that would change this model |
| |
| - A new network surface or REST/websocket endpoint; a new first-class |
| interpreter; a change of any §5a default (e.g., shipping `shiro.ini` enabled, |
| or `notebook.public=false` by default); adding a built-in sandbox for |
| interpreter code; a new notebook-storage backend with different trust. |
| - **A report that cannot be routed to one §13 disposition** is itself evidence |
| the model is incomplete — revise §8/§9 rather than make an ad-hoc call. |
| |
| ## §13 Triage dispositions |
| |
| | Disposition | Meaning | Licensed by | |
| | --- | --- | --- | |
| | `VALID` | Bypasses the authn/authz gate, or lets a user exceed their notebook/role grant, or crosses a tenant/credential/impersonation boundary, with auth configured. | §8, §6, §7 | |
| | `VALID-HARDENING` | No §8 property broken, but the API makes a §11 misuse too easy; hardened at maintainer discretion. | §11 | |
| | `OUT-OF-MODEL: trusted-input` | Requires control of operator config (`shiro.ini`, interpreter JSON, host). | §6 | |
| | `OUT-OF-MODEL: adversary-not-in-scope` | Requires operator/admin privilege, or is a run-capable user executing code within their grant. | §7 | |
| | `OUT-OF-MODEL: non-default-build` | Only manifests under an insecure §5a default the PMC rules dev-only (e.g., anonymous mode, public notebooks, no impersonation). | §5a | |
| | `BY-DESIGN: property-disclaimed` | Concerns interpreter code execution or a property §9 disclaims. | §9 | |
| | `KNOWN-NON-FINDING` | Matches a §11a pattern. | §11a | |
| | `MODEL-GAP` | Cannot be routed above → revise the model. | §12 | |
| |
| ## §14 Open questions for the maintainers |
| |
| Grouped in waves; each states the **proposed answer** followed by the **PMC |
| answer** (recorded by the Apache Zeppelin PMC, 2026-06-11). The core framing — |
| RBAC (Shiro + notebook ACL + URL ACL + impersonation) is the trust boundary, |
| not a sandbox, and a `%sh` from a run-capable user is the product working, not |
| RCE — was confirmed by the PMC and is kept. |
| |
| **Wave 1 — scope & the insecure defaults (these reshape everything):** |
| 1. **Anonymous default.** Proposed: anonymous/no-`shiro.ini` is a *dev- |
| convenience*; the supported production posture requires Shiro **or** a |
| trusted isolated network. So reports against an internet-exposed anonymous |
| instance are `OUT-OF-MODEL: non-default-build`. Correct? (→ §5a, §3, §11a) |
| **→ PMC: confirmed.** |
| 2. **`notebook.public=true` default.** Proposed: public-by-default is intended |
| convenience; operators needing isolation set it false. A "any user can read |
| an empty-ACL note" report is by-design, not a bug. Correct? (→ §5a, §2) |
| **→ PMC: confirmed — by-design.** |
| 3. **Impersonation off by default.** Proposed: without impersonation, all |
| interpreter code legitimately runs as the **server** OS user; this is the |
| documented default and not a vulnerability; multi-tenant OS isolation |
| requires enabling impersonation. Correct? (→ §3, §5a, §9, §11a) |
| **→ PMC: confirmed.** |
| 4. **Binding mode as boundary.** Proposed: shared/scoped/isolated are |
| stability/resource controls, **not** security sandboxes; we should state |
| that explicitly in §9. Agree? Which is the default? (→ §5a, §9) |
| **→ PMC: agreed — the default is `shared`, and no binding mode is a security |
| sandbox.** |
| |
| **Wave 2 — properties & enforcement:** |
| 5. **URL ACL default.** Are `/interpreter`, `/credential`, `/configurations` |
| open to any authenticated role unless `[urls]` restricts them, or is there a |
| built-in admin gate? (→ §5a, §8) |
| **→ PMC: no built-in admin gate — it relies on `shiro.ini [urls]`.** |
| 6. **Server-side ACL enforcement.** Are notebook ACLs + role checks enforced on |
| the **server** for every websocket/REST op (not just hidden in the UI)? Any |
| ops that check only client-side? (→ §6, §8) |
| **→ PMC: enforced server-side; there are no client-side-only checks.** |
| 7. **Credential isolation.** Does the credential store guarantee one user |
| cannot read another user's injected credentials, including via a shared |
| interpreter process? (→ §8, §9) |
| **→ PMC: yes — per-user credentials are isolated.** |
| |
| **Wave 3 — surfaces & limits:** |
| 8. **First-class interpreters.** Which interpreters/modules are supported for |
| security purposes vs. community/unsupported (→ §2/§3 carve-out)? |
| **→ PMC: all bundled interpreters are supported for security purposes |
| (first-class).** |
| 9. **Resource limits.** Any limits on paragraph/result size, websocket rate, or |
| concurrent interpreter launches? Where's the line between in-model pre-auth |
| exhaustion and by-design expensive queries? (→ §6, §8) |
| **→ PMC: `VALID-HARDENING` — please surface. No rate limit or |
| concurrent-launch cap today; this is an area we would like the scan to flag |
| and recommend improvements for.** |
| 10. **Web-UI hardening.** Does enabling `http_security_headers` give CSRF + XSS |
| + clickjacking coverage, or are those partly the operator's job? (→ §9) |
| **→ PMC: `VALID-HARDENING` — please surface. No CSP, and CSRF is |
| Origin-based only; concrete improvements from the scan are welcome.** |
| 11. **Coexistence.** This is a new `THREAT_MODEL.md`; `SECURITY.md` (currently a |
| stub) should point at it as canonical, and the website security pages stay |
| the operator how-to. Agree? (→ meta) |
| **→ PMC: agreed.** |
| |
| ## §15 Machine-readable companion |
| |
| Deferred for v0; a `threat-model.yaml` sidecar (entry points → trust, §5a |
| defaults, §8 properties, §11a suppressions, §13 labels) can be generated once |
| the prose is ratified. |