This is an automated email from the ASF dual-hosted git repository.
jongyoul pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/zeppelin.git
The following commit(s) were added to refs/heads/master by this push:
new b3870e95bb [MINOR] Record PMC answers to the security THREAT_MODEL.md
open questions
b3870e95bb is described below
commit b3870e95bb5d9dfbd83bd3f4682602614ccbde54
Author: Jongyoul Lee <[email protected]>
AuthorDate: Wed Jul 1 23:36:50 2026 +0900
[MINOR] Record PMC answers to the security THREAT_MODEL.md open questions
Follow-up to #5268, which added the security `THREAT_MODEL.md` as a v0
draft for the PMC to review.
This folds the Apache Zeppelin PMC review answers into the document so it
reflects maintainer positions rather than the draft `(inferred)` guesses:
- Records the PMC answer for each open question in §14 (waves 1–3) inline.
- Re-tags the corresponding `(inferred)` claims as `(maintainer)` across
§2/§3/§5a/§6/§8/§9/§11a.
- §5a: records the insecure-default ruling — anonymous-by-default, public
notebooks, impersonation-off, and the shared binding mode are dev-conveniences
/ by-design, so reports against them are `OUT-OF-MODEL: non-default-build`.
- §8: confirms authentication, notebook authorization (server-side), URL
ACL (operator-configured), credential isolation, and impersonation confinement
as committed properties; clarifies that resource/availability is not a
committed property today (treated as `VALID-HARDENING`).
- Keeps the core framing: RBAC is the trust boundary, not a sandbox.
Documentation only; no code changes.
Closes #5275 from jongyoul/threat-model-maintainer-answers.
Signed-off-by: Jongyoul Lee <[email protected]>
---
THREAT_MODEL.md | 133 ++++++++++++++++++++++++++++++++++----------------------
1 file changed, 80 insertions(+), 53 deletions(-)
diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md
index 285a7b3cb4..93a7389d1b 100644
--- a/THREAT_MODEL.md
+++ b/THREAT_MODEL.md
@@ -23,9 +23,10 @@ limitations under the License.
- **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:** **DRAFT v0 — draft-first, not yet maintainer-ratified.** Most
- claims are *(inferred)* from public documentation and the codebase and
- must be confirmed; see §14.
+- **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
@@ -35,7 +36,9 @@ limitations under the License.
- **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).
-- **Draft confidence:** ~18 documented / 0 maintainer / ~24 inferred.
+- **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
@@ -65,7 +68,7 @@ about preventing code execution.
whatever level the deployment's authorization grants anonymous, which by
default is full access.
-**Component-family table** *(inferred — confirm in §14)*:
+**Component-family table** *(maintainer — §14.8)*:
| Family | Entry point | Touches outside process? | In model? |
| --- | --- | --- | --- |
@@ -75,14 +78,14 @@ about preventing code execution.
| 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 | **per-interpreter** — confirm which are supported (§14) |
+| 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. *(inferred — §14)*
+ 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,
@@ -92,9 +95,10 @@ about preventing code execution.
- **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 examples / demo notebooks / unsupported interpreters** — threat-
- modeled separately if at all; integrators should not extend core guarantees
- to them. *(inferred — §14: which interpreters are first-class?)*
+- **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
@@ -147,20 +151,20 @@ 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
| **?** supported posture vs dev-only — §14.1 |
-| `zeppelin.notebook.public` / `ZEPPELIN_NOTEBOOK_PUBLIC` | **`true` → new
notes public** *(documented)* | Empty-ACL note is readable/runnable by any
authenticated (or anonymous) user | **?** §14.2 |
-| 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 | **?** §14.3 |
-| Interpreter binding mode (shared / scoped / isolated) | **shared**
*(inferred)* | Process-level separation between users/notes; "isolated" is a
*stability/resource* boundary, **not** a security sandbox | **?** §14.4 |
-| 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 | **?** §14.5 |
-| HTTPS / security headers (`http_security_headers`) | **off/plain unless
configured** *(documented)* | Credentials + session over plaintext; missing
CSP/XFO | operator responsibility (§10) |
-
-**Insecure-default ruling needed.** For each row whose default is the less-
-secure value, the PMC must rule: is the default the *supported production
-posture* (→ a report against it is `VALID`), or a *dev-convenience operators
-must change* (→ `OUT-OF-MODEL: non-default-build`, and the requirement moves to
-§10)? The public docs lean toward the latter ("strongly recommended… or only
-deploy… in a secured and trusted environment"), but this needs an explicit PMC
-call because it reshapes §8/§10/§11a/§13 at once.
+| 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
@@ -170,15 +174,15 @@ Inputs and their trust (network-service shape — rows are
endpoints/messages):
| --- | --- | --- | --- |
| `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 *(inferred — §14.6)* |
-| `CredentialRestApi` | per-user credentials | **yes** (authenticated user) |
per-user credential isolation *(inferred — §14.7)* |
+| `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: *(inferred — §14)* no documented limits on paragraph size,
-result size, or websocket message rate; resource exhaustion via large
-results / many interpreter launches is plausible and needs a §8 resource line.
+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
@@ -206,32 +210,35 @@ config/secret files or the host outside what their
interpreter identity grants.
## §8 Security properties the project provides
-Each conditional on the relevant §5a knob being set securely. *(All
-*(inferred)* pending §14 — Zeppelin documents the mechanisms but does not
-publish them as committed "properties".)*
+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**. *(inferred)*
+ 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**. *(documented mechanism /
- inferred as a committed property)*
+ 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)*
+ *(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**. *(inferred — §14.7)*
+ 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**. *(documented mechanism / inferred property)*
-6. **Resource/availability** *(inferred — §14)*: **needs a line.** Is an
- unauthenticated request able to spawn interpreters / exhaust memory a bug?
- Propose: pre-auth resource exhaustion is in-model; an authenticated user
- running an expensive query is not. Confirm threshold in §14.
+ **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
@@ -250,17 +257,18 @@ publish them as committed "properties".)*
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**. *(inferred — §14.4)*
+ 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.
- *(inferred — §14)*
+ *(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 (mitigated only if `http_security_headers` + CSRF defenses
-are enabled — confirm coverage in §14); websocket cross-origin. One line each;
-the point is to put integrators on notice.
+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
@@ -297,18 +305,18 @@ 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) *(inferred — §14.3)*
+ 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)*
+ 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)
- *(documented)*
+ *(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) *(inferred)*
+ bypasses the authn/authz gate. (§4 reachability test) *(maintainer)*
## §12 Conditions that would change this model
@@ -334,47 +342,66 @@ The highest-leverage section for keeping scan output
signal-heavy:
## §14 Open questions for the maintainers
-Grouped in waves; each states a **proposed answer** to confirm/correct/strike.
-Every *(inferred)* tag above maps to one of these.
+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