This is an automated email from the ASF dual-hosted git repository.
anshumg pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/solr.git
The following commit(s) were added to refs/heads/main by this push:
new a407a604d78 Add security threat model (THREAT_MODEL.md + SECURITY.md +
AGENTS.md security section) (#4522)
a407a604d78 is described below
commit a407a604d78fc8d998d9c633a170ccd81469ba1a
Author: Jarek Potiuk <[email protected]>
AuthorDate: Mon Jul 13 19:36:01 2026 +0200
Add security threat model (THREAT_MODEL.md + SECURITY.md + AGENTS.md
security section) (#4522)
---
AGENTS.md | 11 ++
SECURITY.md | 41 +++++++
THREAT_MODEL.md | 330 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 files changed, 382 insertions(+)
diff --git a/AGENTS.md b/AGENTS.md
index 70433ba1adc..5a6ce2d70b8 100644
--- a/AGENTS.md
+++ b/AGENTS.md
@@ -56,3 +56,14 @@ While README.md and CONTRIBUTING.md are mainly written for
humans, this file is
- We use the "logchange" tooling to manage our changelog. See
`dev-docs/changelog.adoc` for details and conventions
- To scaffold a new changelog entry, run `gradlew writeChangelog` (JIRA) or
`gradlew writeChangeLogPr` (no JIRA), and then edit the new file located in
`changelog/unreleased/`.
- Do not add a changelog entry before a JIRA issue or a Github PR is assigned,
as one is required.
+
+## Security
+
+For security findings, follow the project's threat model:
+[THREAT_MODEL.md](THREAT_MODEL.md) — the trust boundaries, the load-bearing
+auth+authz / trusted-environment posture, the properties Solr provides vs.
those
+left to the operator (notably: never expose an unauthenticated Solr to an
+untrusted network; SSRF via `shards`/streaming is bounded by operator network
+controls; risky features are off by default), and the recurring non-findings.
+Reporting is via [SECURITY.md](SECURITY.md). Route any scanner/AI-generated
+finding through `THREAT_MODEL.md` section 13 before reporting.
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 00000000000..e1c0ca2c3ca
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,41 @@
+<!--
+ 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.
+-->
+
+# Security Policy
+
+## Reporting a Vulnerability
+
+Apache Solr follows the Apache Software Foundation security process. Report
+suspected vulnerabilities **privately** to the ASF Security Team at
+[[email protected]](mailto:[email protected]) (the Solr PMC is reachable
via
+`[email protected]`). Do **not** open public issues or pull requests for
+security reports. See <https://www.apache.org/security/> and
+<https://solr.apache.org/security.html>.
+
+## Threat Model
+
+Before reporting — and before triaging a tool/fuzzer/AI finding — read
+**[THREAT_MODEL.md](THREAT_MODEL.md)**. Key points:
+
+- Solr is a **search server** meant to run in a **trusted environment with
+ authentication + authorization enabled**. **Never expose an unauthenticated
+ Solr to an untrusted network** — the admin/config/package APIs are powerful
+ by design and must be authz-restricted (THREAT_MODEL.md sections 3, 5a, 9).
+- SSRF via `shards`/streaming-expression remote fetch is **bounded by operator
+ network controls**, not by Solr (section 9/10).
+- Code-execution-adjacent features (Velocity/scripting, remote streaming) are
+ **off by default**; reports requiring them enabled are out of model (section
5a).
+
+Findings outside the model (sections 3/9/11a) are closed citing the relevant
section.
diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md
new file mode 100644
index 00000000000..2407c63621e
--- /dev/null
+++ b/THREAT_MODEL.md
@@ -0,0 +1,330 @@
+<!--
+ 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 Solr — Threat Model
+
+## §1 Header
+
+- **Project:** Apache Solr (`apache/solr`) — a Lucene-based search server.
+ Companion repos in this round: `solr-operator` (Kubernetes operator),
+ `solr-sandbox` (incubating/experimental), `solr-mcp` (MCP server) — modelled
+ at their own trust level or placed out of scope (§2/§3).
+- **Written against:** `main` @ HEAD (2026-06).
+- **Author:** ASF Security team, via the threat-model-producer rubric (Scovetta
+ rubric) at the Solr PMC's request (path 3).
+- **Status:** DRAFT — under maintainer review (2026-06-10). Not yet ratified.
+- **Version binding:** versioned with the project.
+- **Canonical role:** This document is the project's **canonical,
scanner-facing
+ security model** — the authoritative basis for triage when an apparent
+ contradiction arises (confirmed by the Solr PMC, 2026-07). It is deliberately
+ *not* comprehensive of all security information; the operator-facing
+ **"Securing Solr"** reference guide and the published advisories remain the
+ human source of truth for deploying and hardening Solr. The two are
+ complementary — this model is "for scanners", Securing Solr is "for
operators"
+ — and cross-reference each other (see §15). Where they appear to conflict,
this
+ document governs for triage and the PMC addresses the contradiction.
+- **Reporting cross-reference:** §8-violating findings via the ASF security
+ process ([`SECURITY.md`](SECURITY.md)) — reach the Solr PMC security group at
+ [email protected] (see
<https://solr.apache.org/security-reporting.html>);
+ §3/§9 findings closed citing this doc.
+- **Provenance legend:** *(documented)* / *(maintainer)* / *(inferred)* — each
+ *(inferred)* has a §14 open question.
+- **Draft confidence:** ~22 documented / 0 maintainer / 24 inferred.
+
+**What it is.** Solr is a **search server** (HTTP/HTTP2 API) that
+indexes documents and serves queries, deployable as a single node or a
+**SolrCloud** cluster coordinated by ZooKeeper. It exposes query, update
+(indexing), and **admin/config** APIs; supports pluggable **authentication**
+and **authorization**; and can load custom code (the package manager, config
+API, modules). The defining operational fact is Solr's long-standing
+official stance: **Solr is meant to run inside a trusted environment with
+authentication enabled — an unauthenticated Solr must never be exposed to an
+untrusted network.**
+
+## §2 Scope and intended use
+
+Solr is a **network service**, not a library. (Solr does ship a client
+library, **SolrJ** — a separate trust surface, out of scope for this model; a
+later pass can model it on its own.) Roles:
+
+- **Untrusted HTTP client** — only in scope *if Solr is intentionally exposed
+ with authentication enabled*; an unauthenticated Solr is assumed network-
+ isolated (§5a).
+- **Authenticated user** — holds credentials; trusted to authenticate, **not**
+ to exceed their authorization (RuleBasedAuthorizationPlugin / permissions).
+- **Operator/admin** — trusted: owns **all configuration** (auth/authz plus any
+ config / configSet manipulation), locks down admin APIs, controls ZooKeeper,
+ network, and the JVM. There is deliberately no configuration role separate
from
+ admin — configuration *is* an admin-level privilege.
+
+**Component families.**
+
+| Family | Entry point | Privilege / exposure | In model? |
+| --- | --- | --- | --- |
+| Query API | `/select`, request handlers | read; **SSRF surface** (`shards`,
streaming expressions) | **Yes** |
+| Update/indexing API | `/update` | write to index | **Yes** |
+| **Admin / Config / Collections API** | `/admin/*`, ConfigSet/Config API |
**high — changes config, loads code** | **Yes (highest sensitivity)** |
+| Package manager / blob store | package API | **custom code loading** |
**Yes** |
+| Auth/authz plugins | BasicAuth/JWT/Kerberos, RuleBasedAuthz | the security
mechanism | **Yes** |
+| ZooKeeper coupling (SolrCloud) | ZK ensemble | cluster state/config store |
**Yes (trust ZK)** |
+| `solr-operator` | k8s CRDs/controller | in-cluster operator | partial — Q |
+| `solr-mcp` | MCP server | LLM-tool bridge | partial — Q |
+| `solr-sandbox` | experimental | unreleased | No — §3 (unsupported) |
+
+## §3 Out of scope (explicit non-goals)
+
+- **Unauthenticated Solr exposed to an untrusted network.** Solr's documented
+ posture is that it runs in a trusted environment / behind authentication; an
+ operator who exposes an unauthenticated instance to the internet has violated
+ the deployment contract. Findings whose precondition is "reach an
+ unauthenticated admin/config endpoint over an untrusted network" are
+ `OUT-OF-MODEL: non-default-config` / operator misconfiguration (§5a/§9).
*(documented
+ — the canonical Solr security guidance; Q-trustenv confirms.)*
+- **`solr-sandbox`** — experimental/incubating, not a supported release.
Threat-
+ model separately. *(inferred — Q-scope.)*
+- **ZooKeeper security** — Solr trusts its ZK ensemble (it stores config +
cluster
+ state); securing/ACLing ZK is the operator's. *(inferred — Q-zk.)*
+- **The JVM / OS / network the operator runs Solr on.**
+
+## §4 Trust boundaries and data flow
+
+The boundary is the **Solr HTTP API**, gated (in the supported posture) by an
+authentication plugin and an authorization plugin. Once past auth+authz, the
+request is trusted to the extent of the caller's permissions.
+
+```
+HTTP client ─► [auth plugin] ─► [authz plugin: permission for this
path/collection] ─► request handler
+ │
+ query: shards/streaming-expression params can cause Solr to fetch URLs ──►
SSRF surface (§9)
+ admin/config/package: can change config + load custom code ──► privileged,
must be authz-restricted
+SolrCloud: config + cluster state come from ZooKeeper (trusted) ; inter-node
calls (PKI/auth)
+```
+
+**Reachability precondition (triager's test):** a finding is in-model only if
+reachable **with authentication + authorization enabled** by an actor who
+*should not* be able to do it — an unauthenticated request to an auth-protected
+endpoint, or an authenticated user crossing their authorization. A finding that
+requires an unauthenticated, internet-exposed Solr is out of model (§5a).
+
+## §5 Assumptions about the environment
+
+- **Trusted environment:** in the supported posture Solr runs where only
+ authorized clients reach the admin/config/update APIs (auth enabled and/or
+ network isolation). *(documented — Q-trustenv.)*
+- **JVM/JEXL/scripting:** risky features (e.g. the historic Velocity response
+ writer, scripting) are disabled by default and must stay disabled unless the
+ operator accepts the risk. *(documented — post-CVE hardening; Q-features.)*
+- **ZooKeeper** (SolrCloud) is a trusted config/state store. *(inferred —
Q-zk.)*
+- Solr opens network listeners and (via packages/config) can load code by
design.
+
+## §5a Configuration variants — **the central knobs**
+
+1. **Authentication + Authorization** — pluggable, **off by default**. Enabling
+ them (BasicAuth/JWT/Kerberos + RuleBasedAuthorizationPlugin) is what makes
the
+ §8 properties hold. **Off-by-default is the insecure default**; the
supported
+ production posture is auth+authz on (or strict network isolation).
+2. **Risky feature toggles** — Velocity/scripting/JEXL, remote streaming, the
+ ability to load custom code via the config/package API. Defaults are the
+ hardened (off/restricted) values after Solr's CVE history. *(documented.)*
+3. **`-Dsolr.*` system properties** controlling streaming/remote URL access and
+ admin-UI exposure.
+
+**Wave-1 ruling needed (Q-trustenv/Q-features):** confirm that auth+authz-on
(or
+network isolation) is the supported posture, so unauthenticated-exposure
findings
+are `OUT-OF-MODEL: non-default-config`; and which risky toggles, if flipped on,
+move a finding to `OUT-OF-MODEL: non-default-config` vs remain `VALID`.
+
+## §6 Assumptions about inputs
+
+| Boundary | Input | Attacker-controllable? | Enforced by / caller must |
+| --- | --- | --- | --- |
+| any API | credentials / auth token | **yes** | auth plugin verifies |
+| any API | request path + collection | **yes** | authz plugin checks
permission |
+| query | `shards` / `stream.url` / streaming-expression source URLs | **yes**
| restrict remote streaming; network controls (SSRF) |
+| update | document content | **yes** | treated as data; size/rate limits =
operator |
+| admin/config/package | config, custom code, package definitions | **yes
(privileged)** | authz must restrict to admins |
+
+## §7 Adversary model
+
+- **Untrusted HTTP client** — in scope *only* against an intentionally-exposed,
+ auth-enabled Solr (tries to bypass auth, or hit an unprotected path).
+- **Authenticated-but-unauthorized user** — has credentials, tries to
read/write
+ collections or hit admin/config APIs beyond their permissions. In scope —
+ authorization is the defence.
+- **Out of scope:** an attacker who can reach an unauthenticated Solr over an
+ untrusted network (operator violated the deployment contract, §3/§5a); the ZK
+ ensemble operator; the host/JVM.
+
+## §8 Security properties the project provides (auth + authz enabled)
+
+1. **Authentication.** API requests require valid credentials when an auth
+ plugin is configured. *Violation:* auth bypass on a protected endpoint.
+ *Severity:* critical. *(documented; Q for default.)*
+2. **Authorization.** RuleBasedAuthorizationPlugin gates
paths/collections/admin
+ actions by permission. *Violation:* an authenticated user performs an action
+ outside their permissions (esp. admin/config/package). *Severity:* critical.
+ *(inferred — Q-authz.)*
+3. **Risky features off by default.** Code-execution-adjacent features
+ (Velocity/scripting, arbitrary remote streaming) are disabled unless the
+ operator opts in. *Violation:* RCE/SSRF reachable in a default config.
+ *Severity:* critical. *(documented — CVE-driven hardening.)*
+4. **Inter-node auth (SolrCloud).** Node-to-node calls are authenticated
+ (PKI/auth). *Violation:* a rogue actor injecting inter-node requests.
+ *Severity:* high. *(inferred — Q-internode.)*
+5. **Query/index correctness** — results reflect the indexed data and query
+ (a correctness property, not a security one unless it leaks across an authz
+ boundary). *Severity:* correctness. *(inferred.)*
+
+## §9 Security properties the project does *not* provide
+
+- **It is not safe to expose unauthenticated to an untrusted network.** Without
+ auth, the admin/config/package APIs let a caller reconfigure Solr and load
+ code — by design, for a trusted operator. This is the #1 real-world Solr
+ incident class and is **out of model** (operator contract, §3/§5a).
+ - *False friend:* "the admin API let me change config / load a package" is
+ **not** a vulnerability when reached by an authorized admin; it is the
+ feature. It is only `VALID` if reachable across an auth/authz boundary that
+ should have stopped it.
+- **It does not author your authorization rules.** An over-broad permission is
+ an operator decision.
+- **SSRF is bounded by operator network controls.**
`shards`/streaming-expression
+ remote fetches can reach internal URLs; restricting which hosts Solr may
+ contact is operator/network config (§10). *(documented — SSRF guidance.)*
+- **No protection of ZooKeeper / the JVM / the host** (§3).
+- **Well-known classes the operator owns:** SSRF via streaming/shards, RCE via
+ enabling risky features, XXE in document/config parsing (mitigated but
+ config-dependent), and exposure-without-auth.
+
+## §10 Downstream responsibilities (operator)
+
+- **Enable authentication + authorization** (or strictly network-isolate Solr);
+ never expose an unauthenticated instance.
+- **Never place Solr in a public-facing network zone / DMZ.** Keep it in a
+ firewalled internal zone, the same way you would a database — Solr is not
+ designed to be internet-facing. *(maintainer — janhoy.)*
+- **Always enable TLS/SSL** for client and inter-node traffic, to avoid leaking
+ sensitive data or authentication credentials on the wire. *(maintainer —
janhoy.)*
+- **Lock down the admin/config/Collections/package APIs** to admins via authz.
+- **Keep risky features disabled** unless you accept the risk; restrict remote
+ streaming / `shards` to known hosts (SSRF).
+- **Secure ZooKeeper** (ACLs, auth) in SolrCloud.
+- Apply resource/rate limits at the boundary; keep Solr patched.
+
+## §11 Known misuse patterns
+
+- **Exposing an unauthenticated Solr to the internet** (or a shared network).
+- **Leaving the admin/config/package APIs reachable** by non-admins.
+- **Enabling Velocity/scripting/remote-streaming** on an exposed instance.
+- **Unsecured ZooKeeper** holding Solr config (a backdoor into the cluster).
+
+## §11a Known non-findings (recurring false positives)
+
+- **"Admin/Config/Package API allows configuration change / code load"**
reached
+ by an authorized admin (or on an unauthenticated dev instance) — non-finding:
+ it is the feature; `VALID` only across an authz boundary (§8/§9).
+ `OUT-OF-MODEL: non-default-config` when the precondition is unauthenticated
+ exposure.
+- **SSRF via `shards`/streaming** without the operator's host restrictions —
+ the network-control responsibility is the operator's (§9/§10).
+- **Velocity/scripting RCE** when the feature is enabled — `OUT-OF-MODEL:
+ non-default-config` (off by default, §5a).
+- **Findings in `solr-sandbox`** — `OUT-OF-MODEL: unsupported-component` (§3).
+- **ZooKeeper exposure** — operator-owned (§3/§10).
+- **Third-party dependency issues (including Lucene)** — case-by-case: in model
+ only when there's a reasonable Solr-side mitigation; otherwise route to the
+ dependency's own project.
+
+## §12 Conditions that would change this model
+
+- A change to auth/authz defaults, or to the default-disabled risky features.
+- A new code-loading or remote-fetch surface.
+- Promotion of `solr-sandbox` to a release, or `solr-operator`/`solr-mcp`
taking
+ on an untrusted-input role.
+- A report unroutable to a §13 disposition → revise §8/§9.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | A §8 property breaks with auth+authz on, via an in-scope actor. |
§8, §6, §7 |
+| `VALID-HARDENING` | No §8 break, but a §11 misuse is too easy. | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires control of operator config/authz
rules. | §6/§10 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Needs ZK/host/JVM compromise. | §7 |
+| `OUT-OF-MODEL: non-default-config` | Unauthenticated exposure, or an
opted-in risky feature. | §5a |
+| `OUT-OF-MODEL: unsupported-component` | `solr-sandbox` / test code. | §3 |
+| `BY-DESIGN: property-disclaimed` | Admin power, SSRF-needs-network-controls,
exposure-without-auth. | §9 |
+| `KNOWN-NON-FINDING` | Matches §11a. | §11a |
+| `MODEL-GAP` | Unroutable. | triggers §12 |
+
+## §14 Open questions for the maintainers
+
+**Wave 1 — load-bearing.**
+
+- **Q-trustenv.** Confirm the deployment contract: Solr runs in a trusted
+ environment with auth+authz enabled (or network-isolated), so
+ unauthenticated-exposure findings are `OUT-OF-MODEL: non-default-config`.
Point
+ at the canonical guidance you want cited when closing such reports.
(§3/§5a/§9.)
+- **Q-features.** Which risky features are off by default, and for each: is
"on"
+ a supported posture (finding `VALID`) or operator-accepted-risk (finding
+ `OUT-OF-MODEL: non-default-config`)? (Velocity/scripting, remote streaming,
+ package/code loading.) (§5a/§8.)
+- **Q-authz.** Is the §8 authorization claim made for
RuleBasedAuthorizationPlugin
+ specifically, and what is the default-permission posture? (§8.)
+
+**Wave 2 — surface.**
+
+- **Q-ssrf.** Confirm the SSRF position (shards/streaming remote fetch bounded
by
+ operator host controls, not by Solr) and any built-in allow-list. (§9/§10.)
+- **Q-internode / Q-zk.** Inter-node auth guarantees (PKI), and the ZooKeeper
+ trust assumption. (§8/§5.)
+
+**Wave 3 — scope & coexistence.**
+
+- **Q-scope.** Are `solr-operator`, `solr-mcp`, and `solr-sandbox` in scope for
+ this round; at what trust level? (`solr-sandbox` we placed out.) (§2/§3.)
+- **Q-doc.** *(Resolved — Solr PMC, 2026-07.)* Disclosure channel confirmed:
+ `[email protected]` (§1). The model is **canonical** and
scanner-facing —
+ the authoritative basis for resolving apparent contradictions — and
complementary
+ to the operator-facing "Securing Solr" docs; cross-links added (§1/§15).
This PR
+ adds `THREAT_MODEL.md` + `SECURITY.md` and a `## Security` section appended
to the
+ existing `AGENTS.md` (the rest preserved). *(maintainer)*
+
+## §15 Appendix — document roles and existing-policy back-map
+
+**Document roles (confirmed by the Solr PMC, 2026-07).** This `THREAT_MODEL.md`
+is the project's **canonical** security model for automated-scanner purposes —
+the authoritative basis when an apparent contradiction arises. It is
intentionally
+scanner-facing (in/out-of-scope, the §8/§9/§11a property lists, §13 triage
+dispositions) rather than a comprehensive operator handbook. Solr's published,
+**operator-facing** guidance remains the human source of truth for deploying
and
+hardening Solr, and the two cross-reference each other — this model is "for
+scanners", the guidance below is "for operators":
+
+- **"Securing Solr"** (Solr Reference Guide, deployment guide) —
+
<https://solr.apache.org/guide/solr/latest/deployment-guide/securing-solr.html>
+- **Security advisories + reporting** — <https://solr.apache.org/security.html>
+ and <https://solr.apache.org/security-reporting.html>
+
+Where the two appear to conflict, this document governs for triage purposes and
+the PMC addresses the contradiction. This is a role split, not a redundancy:
the
+scanner model constrains what counts as an in-model finding; Securing Solr
tells
+operators how to run Solr safely.
+
+This PR adds `SECURITY.md` (ASF security-process pointer + a link to this
model)
+plus a `## Security` section in the existing `AGENTS.md` (a coding-agent
knowledge
+base — preserved). Each historical CVE maps to a §5a toggle or the
+trusted-environment contract; §8/§9/§11a get refined against the Securing Solr
+docs + advisories in a later pass.