diff --git a/AGENTS.md b/AGENTS.md new file mode 100644 index 0000000000..9c1d948186 --- /dev/null +++ b/AGENTS.md @@ -0,0 +1,30 @@ + + +# Agent Guide for Apache JSPWiki + +This file is read by automated agents (security scanners, code analyzers, +AI assistants) operating on this repository. It points them at the +human-authored references they should consult before producing output. + +## Security + +Security model: [SECURITY.md](./SECURITY.md) → [THREAT_MODEL.md](./THREAT_MODEL.md) + +Agents that scan this repository should consult `SECURITY.md` and the linked +`THREAT_MODEL.md` for the project's threat model — in-scope / out-of-scope +declarations, the security properties claimed and disclaimed, the adversary +model, and known non-findings — before reporting issues. diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000..2fa266da27 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,35 @@ + + +# Security Policy + +## Reporting a Vulnerability + +Apache JSPWiki follows the [Apache Software Foundation security process](https://www.apache.org/security/). +Please report suspected vulnerabilities **privately** to `security@apache.org` (the JSPWiki PMC is +reachable at `private@jspwiki.apache.org`). Do **not** open public GitHub issues or pull requests for +security reports. + +When reporting, include the affected version, a description of the issue, and — if you can — which +security property you believe is violated (see the Threat Model below) and a reproduction. + +## Threat Model + +What JSPWiki considers in scope and out of scope, the security properties it claims and the ones it +explicitly disclaims, the adversary model, and how inbound reports and tool/AI findings are triaged are +documented in [THREAT_MODEL.md](./THREAT_MODEL.md). Reporters and triagers should consult that document +alongside this policy: a finding that violates a claimed property is handled per the process above; a +finding that falls outside the model is closed citing the relevant section. diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md new file mode 100644 index 0000000000..8d56cc880f --- /dev/null +++ b/THREAT_MODEL.md @@ -0,0 +1,377 @@ + + +# Threat Model — Apache JSPWiki + +## §1 Header + +- **Project:** Apache JSPWiki — a feature-rich, WikiWiki-style engine built on + standard Java/Jakarta EE components (servlet container), with page content + authored in JSPWiki markup (or Markdown), server-side plugins and filters, file + attachments, and JAAS-based authentication plus per-page access control lists. +- **Modelled against:** `apache/jspwiki` `master` (HEAD at time of writing, 2026-05-31). +- **Status:** **DRAFT — v0, not yet reviewed by the JSPWiki PMC.** Produced by the ASF + Security team via the `threat-model-producer` rubric + () for the PMC to + react to — confirm, correct, or strike each claim. +- **Version binding:** This model is versioned alongside the project. A report against + release *N* is triaged against the model as it stood at *N*, not at HEAD. +- **Reporting cross-reference:** Findings that violate a §8 property should be reported + privately per `SECURITY.md` / the ASF process (). + Findings that fall under §3 or §9 will be closed citing this document. +- **Provenance legend:** *(documented)* = stated in JSPWiki's own docs/README/source; + *(maintainer)* = confirmed by a JSPWiki PMC member; *(inferred)* = reasoned from code + structure or wiki-engine domain norms, **not yet confirmed** — every *(inferred)* claim + has a matching question in §14. +- **Draft confidence:** ~14 documented / 0 maintainer / ~58 inferred. This is a v0 written + from public artifacts; most claims await PMC ratification. + +JSPWiki is deployed as a web application (a WAR) inside a servlet container. Anonymous and +authenticated web users read and edit pages whose content is rendered from wiki markup to +HTML, may upload and download attachments, and may invoke server-side plugins and filters +embedded in page markup. Who may do what to which page is governed by per-page ACLs, wiki +groups, and a JAAS-backed authentication layer; the deploying operator controls the JVM +security policy (`WEB-INF/jspwiki.policy`), which plugin JARs are installed, and the page / +attachment / user-database storage backends. + +## §2 Scope and intended use + +Primary intended use *(documented)*: a self-hosted collaborative wiki served from a Java +servlet container, with page content collaboratively authored over HTTP, "very detailed +access control and security integration using JAAS" *(documented — README)*, and content +persisted via pluggable page/attachment providers (default: filesystem; +`jspwiki.fileSystemProvider.pageDir`, `jspwiki.basicAttachmentProvider.storageDir`) +*(documented — README)*. + +Caller roles (a web app has no single "caller"): + +- **Anonymous client** — untrusted; whatever an unauthenticated HTTP request can reach. +- **Asserted identity** — a user who supplied a name via cookie but did **not** authenticate + *(inferred)*; trusted only as a convenience label, not as an identity. +- **Authenticated user** — logged in via JAAS; trusted up to the permissions their roles/ACLs grant. +- **Wiki admin** — holds the `Admin` role / `AllPermission`-class grants; trusted for the instance. +- **Operator / deployer** — controls the WAR, `jspwiki.properties`, `jspwiki.policy`, installed + plugin JARs, and storage backends. Fully trusted; **out of model** as an adversary (§3). + +**Component-family table:** + +| Family | Representative entry point | Touches outside process | In model? | +| --- | --- | --- | --- | +| Wiki engine core (page CRUD, references) | `Edit.jsp` / `WikiEngine`, `jspwiki-main` | filesystem (pages) | **Yes** | +| Markup render → HTML | `jspwiki-main` render, `jspwiki-markdown` | no (CPU) | **Yes** | +| Plugins & filters (server-side, invoked from markup) | `[{Plugin}]`, `jspwiki-plugins`, filter chain | varies per plugin (net/fs) | **Yes** (invocation surface) | +| Attachments (upload/download/store) | `Attach.jsp`, `BasicAttachmentProvider` | filesystem | **Yes** | +| AuthN / AuthZ (JAAS, ACLs, groups, user DB) | `auth/*`, `Acl`, `UserManager` | user DB (XML/JDBC), JAAS | **Yes** | +| HTTP / session / UI (JSPs, forms) | `jspwiki-http`, `jspwiki-war` | network | **Yes** | +| Remote APIs (XML-RPC, RSS/Atom feeds) | `jspwiki-xmlrpc` | network | **Yes** | +| Search + content extraction | `jspwiki-tika-searchprovider`, `jspwiki-kendra-searchprovider` | filesystem; Tika parsers; (Kendra → AWS) | **Yes** (parser surface) | +| WYSIWYG editor (client-side) | `jspwiki-wysiwyg` | browser only | No → §3 | +| Portable launcher / Docker demo | `jspwiki-portable`, `docker-files` | — | No → §3 | +| Tests, IT, adapters, sample wikipages | `jspwiki-it-tests`, `*-adapters`, `jspwiki-wikipages` | — | No → §3 | + +## §3 Out of scope (explicit non-goals) + +- **The operator / deployer as adversary.** Anyone who can edit `jspwiki.properties`, + `jspwiki.policy`, deploy plugin JARs, or reach the page/attachment/user-DB storage on disk + has already won; JSPWiki does not defend the instance against its own administrator *(inferred)*. +- **JVM security-policy hardening.** `WEB-INF/jspwiki.policy` configures JVM-level permissions + *(documented — README)*; getting it right is the operator's responsibility (§10), not a + property JSPWiki enforces at runtime. +- **Servlet-container and transport security.** TLS, container auth realms, JVM/OS hardening + are the deployment's job, not JSPWiki's. +- **Plugin / filter *code* supplied by the operator.** Installing a plugin or filter JAR is a + deploy-time, operator-trust action (§9 / §11a). The *invocation* of installed plugins by + untrusted page authors **is** in model. +- **Custom providers / LoginModules** written by the operator (page/attachment/user-DB/auth + backends other than the shipped defaults). +- **Shipped-but-unsupported code:** `jspwiki-portable` (demo launcher), `docker-files`, + `jspwiki-it-tests`, `*-adapters`/`*-adaptees`, and the default `jspwiki-wikipages` content, + which are separately authored and not part of the security contract *(inferred)*. + +## §4 Trust boundaries and data flow + +The trust boundary is the **HTTP request surface**. Every inbound request carries an identity +(anonymous / asserted / authenticated) that the authorization layer resolves to a set of +permissions before any state-changing or ACL-guarded action *(inferred)*. + +Key trust transitions: + +1. **Authoring → storage:** a request with edit rights stores page markup verbatim. The markup + is **untrusted data at rest** — it is attacker-influenced content that later renders into + HTML served to *other* users. The render step (transition 2) is the security-relevant one. +2. **Storage → render → viewer:** stored markup is transformed to HTML and served. This is the + stored-XSS boundary: output must be sanitized so that one user's page content cannot run + script in another user's session *(inferred — see §8/§9)*. +3. **Markup → plugin/filter execution:** `[{PluginName ...}]` and the filter chain execute + server-side Java when a page renders. The author of the markup influences *which* plugin runs + and *with what parameters*; the plugin's code is operator-supplied (§3) *(inferred)*. +4. **Upload → attachment store → download:** uploaded bytes + filename cross into filesystem + storage and are later served back. Path interpretation and content-type handling are the + risk points. +5. **Remote API → engine:** XML-RPC / feed endpoints invoke engine operations under whatever + identity the request authenticates as. + +**Reachability preconditions (the triager's first test):** + +- A finding in the **render/markup** path is in-model only if reachable from stored page content + or a render-time parameter an untrusted author can set. +- A finding in **auth/ACL** is in-model if it lets an identity exceed the permissions its + role/ACL grants. +- A finding in **attachments** is in-model if reachable from an uploaded filename or body. +- A finding in a **plugin/filter** is in-model only if an untrusted author can reach it *and* the + plugin ships/loads by default; a finding that requires an operator to have installed a + non-default plugin is `OUT-OF-MODEL: unsupported-component` (§3) *(inferred — confirm in §14)*. +- A finding reachable only from `jspwiki.properties` / `jspwiki.policy` / disk is out of model (§3). + +## §5 Assumptions about the environment + +- **Runtime:** a standard Java servlet container (Jakarta EE) hosting the WAR *(documented — README)*; + a conformant JVM. +- **Storage:** a filesystem the process can read/write for pages and attachments by default + *(documented — README)*; optionally a JDBC database and/or XML files for the user database and + groups *(inferred)*. +- **Identity backend:** JAAS LoginModule(s) — the default user database, or container/LDAP/custom + modules the operator configures *(documented — JAAS; inferred for specifics)*. +- **Concurrency:** the engine serves concurrent requests; page/attachment providers and the + reference manager are expected to tolerate concurrent access *(inferred)*. +- **What JSPWiki does to its host (inventory, predominantly *(inferred)* — wave-2 confirmation):** + reads/writes the configured page and attachment directories; reads `jspwiki.properties` and + `jspwiki.policy`; may open outbound network connections **only** through plugins/filters/feeds + that fetch URLs (e.g. RSS, image, InterWiki) or through the Kendra search provider; may invoke + Apache Tika parsers over attachment content for indexing. It is **not** assumed to spawn child + processes or install signal handlers *(inferred)*. + +## §5a Build-time and configuration variants + +JSPWiki's security envelope is set far more by `jspwiki.properties` / `jspwiki.policy` than by +compile flags. The knobs below change which §8 properties hold; **defaults are *(inferred)* and +are wave-1 confirmation targets** because an insecure default reshapes §8/§10/§11a/§13 at once. + +| Knob (names *(inferred)*) | Effect on model | Insecure-default? — Maintainer stance | +| --- | --- | --- | +| Default page ACL / `jspwiki.policy` anonymous grants | Whether anonymous users may view/edit/upload | **Open** — is anonymous *edit* on by default the supported posture, or a dev convenience? | +| Self-registration / user creation enabled | Whether anyone may mint an authenticated account | **Open** | +| Login throttling / lockout (`jspwiki.login.throttling`?) | Brute-force resistance of authentication | **Open** | +| Markup engine: JSPWiki vs Markdown (`jspwiki.syntax`?) | Different parser → different XSS/render surface | **Open — which is default?** | +| Raw-HTML / `