This is an automated email from the ASF dual-hosted git repository.

slachiewicz pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/maven.git

commit dff7c7e088276cee1d1361a2c3b96ada2caf6f8b
Author: Jarek Potiuk <[email protected]>
AuthorDate: Sat Jul 4 14:03:21 2026 +0200

    Add a draft security threat model (THREAT_MODEL.md) + SECURITY.md + 
discoverability wiring
    
    Generated-by: Claude Code
---
 .ratignore      |   5 +
 AGENTS.md       |  14 +++
 SECURITY.md     |  16 +++
 THREAT_MODEL.md | 295 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 330 insertions(+)

diff --git a/.ratignore b/.ratignore
new file mode 100644
index 0000000000..0970a5fa59
--- /dev/null
+++ b/.ratignore
@@ -0,0 +1,5 @@
+# Security-model scaffold (carries an SPDX header; exempted
+# from RAT for setups that don't scan Markdown headers).
+THREAT_MODEL.md
+SECURITY.md
+AGENTS.md
diff --git a/AGENTS.md b/AGENTS.md
new file mode 100644
index 0000000000..42b607562e
--- /dev/null
+++ b/AGENTS.md
@@ -0,0 +1,14 @@
+<!-- SPDX-License-Identifier: Apache-2.0
+     https://www.apache.org/legal/release-policy.html -->
+
+# Agent Guide for maven
+
+This file is read by automated agents (security scanners, code
+analyzers, AI assistants) operating on this repository.
+
+## Security
+
+Security model: [SECURITY.md](./SECURITY.md)
+
+Agents that scan this repository should consult `SECURITY.md` and the
+threat model it links before reporting issues.
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 0000000000..c4fce8e7dd
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,16 @@
+<!-- SPDX-License-Identifier: Apache-2.0
+     https://www.apache.org/legal/release-policy.html -->
+
+# Security Policy
+
+## Reporting a Vulnerability
+
+`apache/maven` follows the [Apache Software Foundation security 
process](https://www.apache.org/security/). Please report suspected
+vulnerabilities privately to `[email protected]`; do not open public
+GitHub issues or pull requests for security reports.
+
+## Threat Model
+
+What the project treats as in scope and out of scope, the security
+properties it provides and disclaims, the adversary model, and how
+findings are triaged are documented in [THREAT_MODEL.md](./THREAT_MODEL.md).
diff --git a/THREAT_MODEL.md b/THREAT_MODEL.md
new file mode 100644
index 0000000000..f380fd1a55
--- /dev/null
+++ b/THREAT_MODEL.md
@@ -0,0 +1,295 @@
+<!-- SPDX-License-Identifier: Apache-2.0
+     https://www.apache.org/legal/release-policy.html -->
+
+# Apache Maven — Umbrella Threat Model (v0 DRAFT)
+
+## §1 Header
+
+- **Project family:** Apache Maven (build tool core, runtime, resolver, and 
the maintained plugin set). This is an **umbrella** threat model covering ~26 
repositories across ~34 branch-targets — see §2. Individual repos/branches 
inherit this model except where a §2 row narrows it.
+- **Modeled against:** the current `master`/maintenance branches of the 
in-scope repositories as of the date below. Because Maven is mid-transition 
from the 3.x to the 4.x runtime line, this model carries a **3.x-vs-4.x axis** 
as a first-class distinction rather than describing a single profile (see §2, 
§4, §5a, §6).
+- **Date:** 2026-07-04
+- **Author:** ASF Security team, drafted via the threat-model-producer 
(Scovetta) rubric at the Maven PMC's request (path 3 — Security team drafts, 
Maven PMC reviews).
+- **Status:** **v0 DRAFT — for Maven PMC review.** Not yet ratified. Most 
claims are *(inferred)* and each carries a matching open question in §14.
+- **Version binding:** the threat model is versioned alongside the projects. A 
report against a released Maven core / plugin version *N* is triaged against 
the model as it stood at *N*, not at `master` HEAD. Each branch-target (§2) 
binds to the releases cut from that branch. See §14 Q20.
+- **Reporting cross-reference:** findings that fall under §8 (claimed 
properties) should be reported privately per the ASF process at 
<https://maven.apache.org/security.html> / <https://www.apache.org/security/>. 
Findings that fall under §3 (out of scope) or §9 (properties not provided) — 
including "a plugin executed code", "the published POM differs from the source 
POM", or "checksums do not authenticate the publisher" — will be closed citing 
this document.
+- **Provenance legend:** every non-trivial claim carries exactly one tag:
+  - *(documented)* — stated in Maven's own docs/site; cited inline.
+  - *(maintainer)* — stated by a Maven PMC member in response to this process. 
(None yet — v0.)
+  - *(inferred)* — reasoned from Maven's architecture, domain knowledge, or 
the absence of a feature; **not yet confirmed.** Each *(inferred)* tag names 
the §14 question that must ratify it, e.g. *(inferred, Q5)*.
+- **Draft confidence:** ~26 documented / 0 maintainer / ~59 inferred. This is 
a react-to-me draft, not a ratified model — the heavy *(inferred)* weighting is 
expected for a v0 the PMC has not yet reviewed.
+
+**What Maven is.** Apache Maven is a build-automation and 
dependency-management tool for JVM projects. Given a project description in 
`pom.xml` (the Project Object Model), Maven resolves declared dependencies and 
build **plugins** from configured **repositories** into a local repository 
(`~/.m2/repository`), then executes a lifecycle of plugin goals — compiling, 
testing, packaging, signing, and deploying code. Plugins and build 
**extensions** are ordinary JVM artifacts that Maven downloa [...]
+
+---
+
+## §2 Scope and intended use
+
+**Primary intended use.** Building, testing, packaging, and publishing JVM 
software from a trusted `pom.xml` in a developer or CI environment, resolving 
dependencies and plugins from repositories the operator has chosen to configure 
and trust. *(documented — security.html: "the Maven security model assumes you 
trust the `pom.xml` and the code, dependencies and repositories that are used 
in your build".)*
+
+**Caller roles.** Unlike a network service, Maven has no anonymous client. The 
roles are:
+- **Build author / operator** — writes or vendors the `pom.xml`, 
`settings.xml`, and `.mvn/` config; chooses repositories; runs `mvn`. 
**Trusted** — this actor has already chosen what code to execute. *(inferred, 
Q10)*
+- **Dependency / plugin / extension author** — a third party whose artifact is 
resolved into the build and executed. **Semi-trusted adversary in scope** for 
supply-chain threats (see §7). *(inferred, Q10)*
+- **Repository / mirror operator** — serves artifacts and metadata. 
**Semi-trusted adversary in scope** (compromise, poisoning, MITM on plaintext 
transport). *(inferred, Q10)*
+
+**The 3.x-vs-4.x axis (carried on this table).** Maven is mid-transition. Most 
plugin `master` branches still compile and run against the **Maven 3.9.x** API; 
seven "split" plugins have moved `master` to the **Maven 4** API and keep a 
`*-3.x` maintenance branch on the 3.9.x API. The runtime line changes the trust 
surface (consumer-POM transform, `mvnenc`, resolver 2.x, `mvnup` — all 
Maven-4-only; see §6/§9). Each branch-target is therefore tagged with the 
**Maven API line** it targets, a [...]
+
+| # | Repository / component | Branch-target(s) | Maven API line | Touches 
outside process | In model? |
+| --- | --- | --- | --- | --- | --- |
+| **Core & runtime** | | | | | |
+| 1 | `maven` (core) | `master` (4.0.x); `maven-3.9.x`/3.10.x maint. | 
**both** | reads POM/settings/`~/.m2`, spawns plugin code, network resolve | 
**yes** |
+| 2 | `maven-resolver` | `master` (2.x); `1.9.x` maint. | **both** | HTTP(S) 
transport, local-repo I/O | **yes** |
+| 3 | `maven-mvnd` (daemon) | `master` | 4.x-oriented | long-lived JVM, 
sockets, filesystem | **yes** |
+| 4 | `maven-wrapper` | `master` | line-agnostic | downloads + executes a 
Maven distribution | **yes** |
+| 5 | `maven-build-cache-extension` | `master` | 4.x-oriented | reads/writes 
build-output cache | **yes** |
+| **Single-line master plugins (Maven 3.9.x API)** | | | | | |
+| 6 | `maven-surefire` (surefire + failsafe) | `master` | 3.x | forks test 
JVMs, runs test code | **yes** |
+| 7 | `maven-javadoc-plugin` | `master` | 3.x | forks `javadoc`, unpacks 
archives | **yes** |
+| 8 | `maven-dependency-plugin` | `master` | 3.x | resolves + unpacks 
artifacts | **yes** |
+| 9 | `maven-checkstyle-plugin` | `master` | 3.x | reads source, resolves 
rulesets | **yes** |
+| 10 | `maven-release-plugin` | `master` | 3.x | SCM writes, invokes nested 
Maven | **yes** |
+| 11 | `maven-shade-plugin` | `master` | 3.x | rewrites/merges JAR bytecode | 
**yes** |
+| 12 | `maven-assembly-plugin` | `master` | 3.x | reads/writes archives | 
**yes** |
+| 13 | `maven-scm` | `master` | 3.x | invokes SCM clients (git/svn/…) | 
**yes** |
+| 14 | `maven-site-plugin` | `master` | 3.x | renders site, resolves 
skins/reports | **yes** |
+| 15 | `maven-enforcer` | `master` | 3.x | evaluates rules over the build | 
**yes** |
+| 16 | `maven-archetype` | `master` | 3.x | scaffolds projects from templates 
| **yes** |
+| 17 | `maven-resolver-ant-tasks` | `master` | 3.x | Ant-side 
resolution/transport | **yes** |
+| 18 | `maven-indexer` | `master` | 3.x | parses repository index metadata | 
**yes** |
+| **Split plugins — master on Maven 4 API + `*-3.x` maintenance** | | | | | |
+| 19 | `maven-compiler-plugin` | `master` (M4); `*-3.x` | **both (two 
targets)** | forks/embeds compiler, reads source | **yes** |
+| 20 | `maven-jar-plugin` | `master` (M4); `*-3.x` | **both** | writes JARs | 
**yes** |
+| 21 | `maven-clean-plugin` | `master` (M4); `*-3.x` | **both** | deletes 
filesystem paths | **yes** |
+| 22 | `maven-deploy-plugin` | `master` (M4); `*-3.x` | **both** | uploads 
artifacts to remote repo | **yes** |
+| 23 | `maven-install-plugin` | `master` (M4); `*-3.x` | **both** | writes to 
local repo | **yes** |
+| 24 | `maven-resources-plugin` | `master` (M4); `*-3.x` | **both** | 
copies/filters resource files | **yes** |
+| 25 | `maven-source-plugin` | `master` (M4); `*-3.x` | **both** | packages 
source JARs | **yes** |
+
+Counting the two targets each for rows 1, 2, and 19–25 yields ~34 
branch-targets across ~25 repositories. `mvnup` and `mvnenc` ship inside the 
Maven 4 core distribution (row 1, `master`) and are in model. See §14 Q3.
+
+---
+
+## §3 Out of scope (explicit non-goals)
+
+- **Parent POMs** (`maven-parent`, `apache` parent, plugin/plugins parents) — 
configuration aggregation, no runtime surface of their own. *(inferred, Q2)*
+- **`maven-studies`** — experimental/incubating code, not a supported product. 
*(inferred, Q2)*
+- **SVN mirrors** of Git repositories — read-only mirrors, no independent 
surface. *(inferred, Q2)*
+- **CI / build infrastructure** (Jenkins jobs, GitHub Actions, ASF Infra) — 
SDLC/build-hygiene, out of layer per the rubric. *(inferred, Q2)*
+- **Project website, skins, and documentation content** (`maven-site`, 
Fluido/skin projects) — presentation, not the tool. *(inferred, Q2)*
+- **Building untrusted code without operator-provided isolation.** Maven does 
not aim to safely build code it has been told to build. *(documented — 
security.html: "If you want to use Maven to build untrusted code, it is up to 
you to provide the required isolation.")*
+- **The security of the artifacts a build produces.** Whether *your* code is 
vulnerable is your project's concern, not Maven's. *(inferred, Q2)*
+- **Build/release/SDLC hygiene** of the Maven repos themselves (action 
pinning, reproducible builds, 2FA) — out of scope per the threat-model rubric.
+
+---
+
+## §4 Trust boundaries and data flow
+
+Maven is not a network service; it is a **local process that pulls remote 
inputs and executes them.** The meaningful trust transitions are:
+
+1. **Local config → build JVM (trusted → trusted).** `pom.xml`, 
`settings.xml`, `.mvn/extensions.xml`, `.mvn/maven.config`, and the existing 
contents of `~/.m2/repository` are treated as **already-authorized by the 
operator**. Malicious content here is out of model — the operator supplying it 
has already won. *(inferred, Q5)* The exception the operator must understand: 
cloning and building an **untrusted** third-party project makes that project's 
`pom.xml`/`.mvn/` a trusted input to Mave [...]
+
+2. **Remote repository → local repository (semi-trusted → 
trusted-on-arrival).** This is the **primary security boundary.** Artifacts and 
metadata arrive over resolver transport from repositories/mirrors. Maven 
verifies **transport integrity** (checksums) but does **not**, in core, verify 
**publisher authenticity** (PGP signatures) — see §8/§9. Once an artifact lands 
in `~/.m2/repository` it is thereafter treated as trusted local input 
(transition 1). A poisoned local repo is out of mode [...]
+
+3. **Resolved plugin/extension → arbitrary code execution (BY DESIGN).** A 
resolved plugin, build extension, or `${...}`-driven lifecycle binding runs as 
arbitrary JVM code in the build. There is **no trust boundary here** — crossing 
from "declared in POM" to "executing" is the intended behavior, not a 
violation. *(documented — security.html trust statement.)*
+
+**Maven-4-only transitions (in model only for 4.x branch-targets):**
+- **Build POM → consumer POM transform.** At `install`/`deploy`, Maven 4 
rewrites the source `pom.xml` into a flattened **consumer POM** that is what 
downstream actually resolves. The **published POM deliberately differs from the 
source POM.** *(documented — whatsnewinmaven4: consumer POM is flattened, drops 
parent references, flattens BOM imports, keeps only compile/runtime transitive 
deps.)* See §9 / §11a / Q7.
+- **`mvnup` → source `pom.xml` rewrite.** The Maven 4 upgrade tool **writes 
back into the user's `pom.xml`** in place. *(documented — whatsnewinmaven4.)* 
The write target (the source tree) is a trusted output location; the transform 
inputs are the trusted POM. *(inferred, Q8)* See Q8.
+- **`mvnenc` → encrypted `settings-security`/vault.** Maven 4 reworks settings 
encryption from Maven 3's obfuscation to real encryption with optional external 
vault. *(documented — whatsnewinmaven4.)* Key/vault material is outside Maven's 
boundary (§10). *(inferred, Q9)*
+
+**Reachability precondition (the triager's first test).** A finding is 
in-model only if it is reachable from a **remote-repository-supplied** 
artifact/metadata byte (transition 2), from **resolver transport**, or from the 
**Maven-4 transform surfaces** above — *without* first assuming the operator 
supplied malicious local config or a pre-poisoned `~/.m2`. A finding that 
requires attacker control of `pom.xml`/`settings.xml`/`~/.m2` on a build the 
operator authored is `OUT-OF-MODEL: truste [...]
+
+---
+
+## §5 Assumptions about the environment
+
+- **Runtime.** A JVM. Maven 4 core requires **Java 17+**; the 3.x line runs on 
older JDKs. *(documented — whatsnewinmaven4.)*
+- **Operator-controlled machine.** Maven assumes it runs on a host the 
operator controls; local filesystem, environment variables, and `~/.m2` are 
trusted. *(inferred, Q5)*
+- **Network.** Maven reaches repositories over operator-configured URLs. 
Plaintext `http://` external repositories are treated as untrusted and are 
**blocked by default** in the shipped `conf/settings.xml` via the 
`external:http:*` mirror / `<blocked>` mechanism. *(documented — security.html, 
CVE-2021-26291 mitigation.)*
+- **Clock / entropy.** Not security-load-bearing in core. *(inferred, Q2)*
+- **What Maven does to its host (side-effect inventory).** Maven **does** 
write to `~/.m2/repository` and the project `target/`, open network connections 
to configured repositories, fork child JVMs/processes (plugins, test runners, 
compilers, SCM clients), and read environment variables and `settings.xml` 
(which may contain **plaintext or obfuscated credentials**). `mvnd` 
additionally runs a **long-lived daemon JVM** reused across builds. These are 
all intended. *(inferred, Q5, Q12)*
+
+## §5a Build-time and configuration variants (the knobs that move the model)
+
+| Knob | Default | Effect on model | Maintainer stance |
+| --- | --- | --- | --- |
+| Resolver **checksum policy** (`-C`/`--strict-checksums` vs 
`-c`/`--lax-checksums`; `checksumPolicy`) | `warn` (lax) | `warn` logs but does 
**not** fail on checksum mismatch → integrity not enforced by default | to 
confirm — Q4 |
+| PGP **signature verification** | **off** in core (no signature check) | 
authenticity of publisher unverified unless an extension is added | to confirm 
— Q6 |
+| `maven.consumer.pom.flatten` (M4) | on for install/deploy | published POM ≠ 
source POM | to confirm — Q7 |
+| `settings.xml` credential encryption | Maven 3: obfuscation; Maven 4: 
`mvnenc` real encryption | master-password/vault protects at-rest creds | to 
confirm — Q9 |
+| `external:http:*` repo blocking | **on** (shipped `settings.xml`) | 
plaintext external repos rejected | documented (security.html) |
+| `mvnd` daemon reuse | on when invoked as `mvnd` | cross-build JVM state 
reuse | to confirm — Q12 |
+
+**Insecure-default question (Q4, wave 1).** Resolver's default checksum policy 
is `warn`, not `fail`. Is `warn` the **supported production posture** (so "a 
corrupted artifact was accepted with only a warning" is 
`BY-DESIGN`/downstream-responsibility), or is `fail`/`--strict-checksums` the 
intended posture for anything trust-sensitive (making a silent-accept report 
`VALID-HARDENING`)? This reshapes §8, §9, §10, §11a, §13 at once.
+
+---
+
+## §6 Assumptions about inputs
+
+Maven's inputs split cleanly into **operator-supplied (trusted)** and 
**repository-supplied (semi-trusted)**. Where the trust posture differs between 
the 3.x and 4.x lines, the table has a `Line` column.
+
+| Input | Line | Origin | Attacker-controllable? | Caller/operator must 
enforce |
+| --- | --- | --- | --- | --- |
+| `pom.xml` (source/build POM) | both | operator's project | **no** — trusted 
local config | don't build untrusted projects unsandboxed (§10) *(inferred, 
Q5)* |
+| `settings.xml` (+ `settings-security`) | both | operator `~/.m2` | **no** — 
trusted; holds credentials | protect the file / key material *(inferred, Q5, 
Q9)* |
+| `.mvn/extensions.xml`, `.mvn/maven.config` | both | operator project | 
**no** — trusted; loads extensions as code | same as `pom.xml` *(inferred, Q5)* 
|
+| Existing `~/.m2/repository` contents | both | prior builds | **no** — 
trusted-on-arrival | don't share a poisoned local repo *(inferred, Q11)* |
+| **Resolved dependency/plugin/extension bytes** | both | remote repo/mirror | 
**yes** | checksum policy; add signature verification; pin versions *(inferred, 
Q4, Q6)* |
+| **Repository metadata** (`maven-metadata.xml`, checksums, index) | both | 
remote repo/mirror | **yes** | resolver parses these before trust is 
established *(inferred, Q4, Q18)* |
+| Resolver **transport** (HTTP responses, redirects, TLS) | both | 
network/mirror | **yes** | HTTPS; block plaintext external repos *(documented — 
security.html)* |
+| Archive contents unpacked by plugins (zip/tar/jar) | both | remote artifact 
| **yes** | path-traversal (`zip-slip`) surface in unpack plugins *(documented 
— security.html Plexus Archiver)* |
+| **Consumer-POM transform input** (`mvn deploy`) | **4.x only** | operator 
project → published | source **no**; the *published* result is a new surface 
for downstream | verify what you publish matches intent *(inferred, Q7)* |
+| **`mvnup` rewrite input** | **4.x only** | operator `pom.xml` | **no** — 
trusted, but written back in place | review the diff `mvnup` produces 
*(inferred, Q8)* |
+| **`mvnenc` secrets / vault** | **4.x only** | operator | **no** — trusted | 
manage the master key/vault (§10) *(inferred, Q9)* |
+
+**Size/shape.** Maven imposes no general bound on POM size, dependency-graph 
depth, or artifact size; resolution of a hostile dependency graph (deep 
transitive fan-out, decompression of hostile archives) is a resource surface. 
*(inferred, Q17)*
+
+---
+
+## §7 Adversary model
+
+**In scope:**
+- **Malicious dependency, plugin, or extension author** whose artifact is 
resolved into a build. Capability: run arbitrary code in the build JVM (that 
part is by design — §9), *and* attempt to exploit resolver/plugin parsing 
(archive path traversal, metadata parsing) **before/around** that execution, or 
poison other builds via the shared local repo. *(inferred, Q10)*
+- **Compromised or malicious repository / mirror operator.** Capability: serve 
tampered artifacts, tampered metadata/checksums, or malicious redirects. 
Bounded by checksum/signature posture (§5a) and HTTPS. *(inferred, Q10)*
+- **Network attacker (MITM)** on any plaintext (`http://`) transport the 
operator has not blocked. *(documented — security.html, 
CVE-2021-26291/CVE-2013-0253/CVE-2012-6153.)*
+
+**Explicitly out of scope:**
+- **The operator running the build**, and anyone with write access to the 
operator's `pom.xml`, `settings.xml`, `.mvn/`, or `~/.m2`. They have already 
chosen the code that runs. *(documented — security.html trust statement.)*
+- **A local co-tenant with filesystem access** to `~/.m2` or the source tree. 
*(inferred, Q5)*
+- **The author of the project being built**, when the operator has chosen to 
build that project (see §11 for the untrusted-project misuse). *(inferred, Q10)*
+
+---
+
+## §8 Security properties the project provides
+
+For each: property → violation symptom → severity → provenance.
+
+1. **Transport integrity via checksums.** For each resolved artifact, resolver 
compares the downloaded bytes against the repository's published checksum. 
*Symptom of break:* a tampered artifact is accepted as valid. *Severity:* 
**high** (but note the default policy only **warns** — §5a/Q4). *(inferred, Q4)*
+2. **Plaintext-external-repo rejection.** The shipped `conf/settings.xml` 
blocks `external:http:*` so a plaintext external mirror cannot silently 
substitute artifacts. *Symptom:* a MITM downgrades resolution to plaintext and 
substitutes bytes. *Severity:* **high.** *(documented — security.html.)*
+3. **Credential-at-rest protection (`mvnenc`, Maven 4).** Server credentials 
in `settings.xml` can be encrypted (real encryption in 4.x; obfuscation only in 
3.x). *Symptom:* plaintext credential recovery from `settings.xml`. *Severity:* 
**medium** (3.x is obfuscation, not a confidentiality guarantee — §9). 
*(documented — whatsnewinmaven4.)*
+4. **Consumer-POM minimization (Maven 4).** The published consumer POM omits 
build-internal detail (internal plugin config, non-inherited structure), 
reducing accidental exposure of internal repository URLs/config to downstream. 
*Symptom:* internal config leaks into the published POM. *Severity:* 
**low–medium.** *(documented — whatsnewinmaven4.)*
+5. **Resolver API encapsulation (Maven 4).** Resolver 2.x is hidden behind the 
new Maven API; plugins no longer call it directly, shrinking the plugin-facing 
transport attack surface. *Symptom:* a plugin drives transport in an unsafe 
way. *Severity:* **low.** *(documented — whatsnewinmaven4.)*
+6. **JVM memory safety.** Maven is managed JVM code; classic memory-corruption 
(OOB, UAF) is not the threat class. *Symptom:* JVM crash/`OutOfMemoryError` — a 
robustness bug, not memory unsafety. *Severity:* **correctness-only** unless it 
enables the above. *(inferred, Q2)*
+
+**No resource-exhaustion guarantee is made.** Maven does not bound POM size, 
transitive-graph size, archive decompression, or plugin CPU/memory. A hostile 
dependency graph or archive that exhausts memory/CPU is **not** a §8 violation. 
*(inferred, Q17)* See §9.
+
+---
+
+## §9 Security properties the project does *not* provide
+
+This is the load-bearing section for triage. State each plainly.
+
+- **No build/plugin sandbox — arbitrary code execution during a build is BY 
DESIGN.** Maven executes the `pom.xml` it is given, which "commonly includes 
compiling and running the associated code and using plugins and dependencies". 
A plugin, extension, test, or lifecycle binding running arbitrary code is **the 
intended behavior, not a vulnerability.** *(documented — security.html.)* **A 
scanner reporting "plugin/extension/test executes arbitrary code" is a 
`BY-DESIGN` non-finding, not a  [...]
+- **No publisher-authenticity verification in core.** Checksums prove 
*integrity in transit*, not *who published the artifact*. Maven core/resolver 
does **not** verify PGP signatures of dependencies or plugins by default; a 
correctly-checksummed but attacker-published artifact is accepted. Signature 
verification requires an add-on extension the operator installs. *(inferred, 
Q6)* **False friend:** a checksum is not a signature and not a MAC — it 
authenticates nothing about origin.
+- **No defense against a poisoned local repository.** Once bytes are in 
`~/.m2/repository`, they are trusted. Maven does not re-validate them against a 
remote source on each build. *(inferred, Q11)*
+- **Maven 3 credential encryption is obfuscation, not encryption.** The 3.x 
master-password scheme does not provide confidentiality against an attacker who 
reads both `settings.xml` and `settings-security.xml`. Use `mvnenc` (4.x). 
*(documented — whatsnewinmaven4: Maven 3's scheme "more accurately called 
password obfuscation".)*
+- **The published (consumer) POM is deliberately not byte-identical to the 
source POM (Maven 4).** The transform is a feature. **A finding of the form 
"the deployed POM does not match the repo `pom.xml`" is `BY-DESIGN`, not 
tampering.** *(documented — whatsnewinmaven4.)* See §11a.
+- **No resource-exhaustion / DoS defense.** No bound on transitive-dependency 
fan-out, POM/XML entity expansion, or hostile-archive decompression ("zip/tar 
bombs"). *(inferred, Q17)* Well-known classes Maven leaves to the 
operator/ecosystem: **dependency-confusion** (name-squatting across 
repositories), **typosquatting**, **XML entity expansion in POM/metadata 
parsing**, and **archive path traversal on unpack** (the Plexus Archiver class 
— *documented*).
+- **No guarantee that `mvnup`'s rewrite is safe to apply unreviewed** — it 
rewrites your `pom.xml`; the operator must review the diff. *(inferred, Q8)*
+- **No cross-build isolation for `mvnd`.** The daemon reuses a JVM across 
builds; it is not an isolation boundary between projects built by the same 
daemon. *(inferred, Q12)*
+- **No integrity guarantee for shared build caches.** 
`maven-build-cache-extension` keys outputs by hashes; a shared/remote cache is 
only as trustworthy as its writers. *(inferred, Q14)*
+- **No trust anchor in `maven-wrapper`.** `mvnw` downloads and executes 
whatever Maven distribution `distributionUrl` names; checksum pinning 
(`distributionSha256Sum`) is optional and operator-supplied. *(inferred, Q13)*
+
+---
+
+## §10 Downstream (operator) responsibilities
+
+For Maven, "downstream" is the **build author / operator / CI owner.**
+
+- **Only build code and POMs you trust** — or provide OS/container isolation 
yourself. *(documented — security.html.)*
+- **Curate your repositories and mirrors.** Prefer HTTPS; keep the shipped 
`external:http:*` block; use a controlled proxy/mirror rather than arbitrary 
third-party repos. *(documented — security.html.)*
+- **Choose your checksum/signature posture deliberately.** Enable 
`--strict-checksums` and add signature-verification tooling if your threat 
model needs publisher authenticity. *(inferred, Q4, Q6)*
+- **Pin versions** (avoid version ranges / `LATEST`/`RELEASE` for plugins and 
dependencies) to reduce dependency-confusion and surprise-upgrade risk. 
*(inferred, Q17)*
+- **Protect `settings.xml` and key material.** Use `mvnenc` (4.x); manage the 
master password / external vault; never commit credentials. *(inferred, Q9)*
+- **Review `mvnup` diffs** before committing the rewritten `pom.xml`. 
*(inferred, Q8)*
+- **Pin the wrapper** (`distributionSha256Sum`, `wrapperSha256Sum`) if you 
commit `mvnw` into a repo others run. *(inferred, Q13)*
+- **Treat shared build caches as a trust boundary** — sign/authenticate cache 
writers. *(inferred, Q14)*
+
+---
+
+## §11 Known misuse patterns
+
+- **Building an untrusted third-party project unsandboxed.** Cloning a random 
repo and running `mvn ...` (or opening it in an IDE that auto-imports) executes 
that project's plugins/extensions as you. *What to do instead:* build unknown 
projects only inside a disposable container/VM. *(inferred, Q10)*
+- **Adding an untrusted `http://` repository or disabling the 
`external:http:*` block.** Reopens the MITM/substitution vector CVE-2021-26291 
closed. *(documented — security.html.)*
+- **Relying on Maven 3 password "encryption" as confidentiality.** It is 
obfuscation; an attacker with both files recovers the secret. *(documented — 
whatsnewinmaven4.)*
+- **Assuming checksums authenticate the publisher.** They only detect transit 
corruption. *(inferred, Q6)*
+- **Running `mvnd` across mutually-distrusting projects and assuming 
isolation.** The daemon JVM is shared. *(inferred, Q12)*
+- **Committing a `mvnw` wrapper with an unpinned `distributionUrl`.** Anyone 
who moves/poisons that URL controls the Maven that runs. *(inferred, Q13)*
+
+## §11a Known non-findings (recurring false positives)
+
+Feed this list to scanners as a suppression / negative prompt.
+
+- **"A Maven plugin / build extension / test / lifecycle goal executes 
arbitrary code."** `BY-DESIGN` per §9 — this is Maven's core function, not a 
vulnerability. Applies to `exec`-style goals, code-generating plugins, 
`surefire`-forked test code, `shade` bytecode rewriting, etc. *(documented — 
security.html.)*
+- **"The deployed/published POM differs from the source `pom.xml`."** 
`BY-DESIGN` per §9 (Maven 4 consumer-POM transform). Not tampering. 
*(documented — whatsnewinmaven4.)*
+- **Dependabot / SCA alerts on `test`-scope, `provided`-scope, or 
integration-test-only dependencies of the Maven repos themselves.** These do 
not ship in released Maven artifacts and are not reachable in a consuming build 
→ `OUT-OF-MODEL: trusted-input`/unsupported-surface for the Maven product. 
*(inferred, Q17)*
+- **Alerts on transitive dependencies pulled only by the build/test harness** 
(not by the plugin/core runtime artifact). Same routing. *(inferred, Q17)*
+- **"`settings.xml` contains a credential."** Expected — that is what 
`settings.xml` is for; confidentiality is `mvnenc`'s job at rest, not a finding 
against the file's existence. *(inferred, Q9)*
+- **"Checksum policy defaults to warn, not fail."** Routed by the Q4 ruling — 
pending confirmation this is `BY-DESIGN`/downstream, not a bug. *(inferred, Q4)*
+- **"Maven downloads and runs code from the internet."** `BY-DESIGN` — the 
resolve-and-execute model per §4/§9. *(documented — security.html.)*
+
+---
+
+## §12 Conditions that would change this model
+
+- Core adopts **default publisher-authenticity verification** (signature 
checking on by default) — rewrites §8/§9.
+- The resolver **default checksum policy** changes from `warn` to `fail` — 
flips Q4's disposition.
+- A new **Maven-4 transform** or tool that reads remote/untrusted input into a 
rewrite (beyond `mvnup`/consumer-POM).
+- The **3.x line reaches EOL** or a split plugin drops its `*-3.x` branch — 
removes a branch-target column.
+- `mvnd` or `build-cache-extension` gains a **network-shared** default surface 
(remote daemon, remote cache) — adds a network adversary.
+- **Any finding that cannot be routed to a §13 disposition** — that is a 
`MODEL-GAP` and the model must be revised (add the property to §8/§9), not 
decided ad hoc.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a claimed property via a repo/mirror/transport-controlled 
input or a Maven-4 transform surface. | §8, §6, §7 |
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse is easy enough 
that the project elects to harden (e.g. tighten a default). | §11, §5a |
+| `OUT-OF-MODEL: trusted-input` | Requires attacker control of 
`pom.xml`/`settings.xml`/`.mvn/`/`~/.m2` on an operator-authored build. | §6 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires the operator, a local 
co-tenant, or the built project's author (when the operator chose to build it). 
| §7 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in parent POMs, 
`maven-studies`, site/skins, SVN mirrors, or CI infra. | §3 |
+| `OUT-OF-MODEL: non-default-build` | Only manifests when a §5a default is 
flipped to the less-safe value (e.g. `external:http:*` block removed). | §5a |
+| `BY-DESIGN: property-disclaimed` | Plugin/extension/test code execution; 
published-POM ≠ source-POM; checksum ≠ signature; resolve-and-run. | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry (test-scope SCA alerts, 
`settings.xml`-holds-a-credential, etc.). | §11a |
+| `MODEL-GAP` | Cannot be routed above — triggers a model revision. | §12 |
+
+---
+
+## §14 Open questions for the maintainers
+
+Each *(inferred)* tag in the body routes to one question below. Every question 
states a **proposed answer** to confirm/correct. Grouped in waves.
+
+**Wave 1 — scope & the 3.x/4.x axis (shapes everything else):**
+- **Q1.** We treat the **3.x-vs-4.x split** as the primary axis: a finding is 
triaged against the Maven API line of the specific branch-target, and 
Maven-4-only surfaces (consumer POM, `mvnenc`, resolver 2.x, `mvnup`) are out 
of model for 3.x targets. *Proposed: correct.* (→ §2, §4, §6)
+- **Q2.** Out-of-scope set — parent POMs, `maven-studies`, SVN mirrors, 
CI/infra, site/skins, and "the security of the artifacts your build produces" — 
is right and complete. *Proposed: correct.* (→ §3)
+- **Q3.** `mvnup` and `mvnenc` ship inside the Maven 4 core distribution (repo 
#1 `master`) and are in model as part of core, not as separate products. 
*Proposed: correct.* (→ §2)
+- **Q4.** *(Insecure-default.)* Resolver's default checksum policy is `warn`, 
not `fail`. Is `warn` the supported posture (silent-accept-on-mismatch = 
`BY-DESIGN`/downstream), or is `--strict-checksums` intended for 
trust-sensitive use (silent-accept = `VALID-HARDENING`)? (→ §5a, §8, §9, §11a)
+
+**Wave 2 — inputs, trust, and the Maven-4 surfaces:**
+- **Q5.** `pom.xml`, `settings.xml`, `.mvn/` config, and existing `~/.m2` 
contents are **trusted local inputs**; findings requiring attacker control of 
them (on an operator-authored build) are out of model. *Proposed: correct.* (→ 
§4, §6)
+- **Q6.** Maven core/resolver does **not** verify PGP publisher signatures by 
default; authenticity verification is an operator-installed extension. 
*Proposed: correct — this is a disclaimed property (§9), and "no signature 
check" is not a core finding.* (→ §8, §9)
+- **Q7.** The Maven-4 **consumer/build-POM transform** is by design; 
"published POM ≠ source POM" is a `BY-DESIGN` non-finding. Are there transform 
behaviors (e.g. what the consumer POM *retains*) that you *would* consider 
security-relevant? *Proposed: transform itself is by design; retention of 
internal repo URLs would be the concern.* (→ §9, §11a)
+- **Q8.** `mvnup` rewrites the operator's `pom.xml` in place from trusted 
inputs; the operator is expected to review the diff. Does `mvnup` ever read 
**untrusted/remote** input into that rewrite (which would make it an in-model 
input surface)? *Proposed: inputs are trusted; operator reviews the diff.* (→ 
§4, §6, §9, §10)
+- **Q9.** `mvnenc` provides at-rest credential encryption; master-key/vault 
management is a downstream responsibility, and "`settings.xml` contains a 
credential" is not a finding. *Proposed: correct.* (→ §5a, §9, §10, §11a)
+
+**Wave 3 — adversary, resolver, runtime components:**
+- **Q10.** Adversary model — in scope: malicious dependency/plugin/extension 
author, compromised repo/mirror, plaintext-transport MITM; out of scope: 
operator, local co-tenant, and the built project's author when the operator 
chose to build it. *Proposed: correct.* (→ §2, §7, §11)
+- **Q11.** A **pre-poisoned local repository** (`~/.m2/repository`) is out of 
model (trusted-on-arrival); poisoning it *over the wire* during resolution is 
in model. *Proposed: correct.* (→ §4, §9)
+- **Q12.** `mvnd` is **not** an isolation boundary between projects built by 
the same daemon; cross-build state isolation is not a claimed property. 
*Proposed: correct.* (→ §5, §9, §11)
+- **Q13.** `maven-wrapper` executes whatever `distributionUrl` names; checksum 
pinning is optional/operator-supplied and there is no built-in trust anchor. 
*Proposed: correct — disclaimed.* (→ §9, §10, §11)
+- **Q14.** `maven-build-cache-extension` makes **no integrity guarantee for 
shared/remote caches**; authenticating cache writers is a downstream 
responsibility. *Proposed: correct.* (→ §9, §10)
+
+**Wave 4 — plugin branch-targets & non-findings:**
+- **Q15.** For the seven **split plugins**, the `*-3.x` branch targets the 
Maven 3.9 API and shares most code with `master`; a finding present in shared 
code applies to **both** branch-targets, while a finding in Maven-4-only master 
code applies only to the 4.x target. *Proposed: correct.* (→ §2)
+- **Q16.** The 13 **single-line `master` plugins** require Maven **3.9.x** at 
runtime despite living on `master` (no `*-3.x` branch needed). *Proposed: 
correct.* (→ §2)
+- **Q17.** Known non-findings for **SCA/Dependabot noise** — 
`test`/`provided`/IT-only and build-harness-only transitive deps of the Maven 
repos are not reachable in the shipped product → out of model; and no 
resource-exhaustion (dependency-graph/XML-entity/archive-bomb) guarantee is 
made. *Proposed: correct and representative.* (→ §6, §8, §9, §11a)
+- **Q18.** `maven-resolver-ant-tasks` and `maven-indexer` inherit the same 
repo-supplied-metadata trust posture as core resolver (index/metadata parsing 
is an in-model input). *Proposed: correct.* (→ §2, §6)
+
+**Wave 5 — meta / process:**
+- **Q19.** **There is no `SECURITY.md` in `apache/maven` `master`** (verified 
404); the documented model lives on `maven.apache.org/security.html`. For the 
scan to mechanically discover this model, where should the canonical 
`THREAT_MODEL.md` live (per-repo vs one umbrella), and can an `AGENTS.md → 
SECURITY.md → THREAT_MODEL.md` discoverability chain be added? *Proposed: one 
umbrella model, linked from each repo's `SECURITY.md`/`AGENTS.md`.* (→ §1)
+- **Q20.** **Version binding** — each branch-target's model binds to the 
releases cut from that branch; a report against Maven core 3.9.x is triaged 
against the 3.x profile, not the 4.x `master` surface. *Proposed: correct.* (→ 
§1)
+
+---
+
+## §15 Machine-readable companion
+
+Deferred for v0. Once the PMC ratifies, emit a `threat-model.yaml` sidecar 
indexing: branch-target → Maven API line (§2); entry point → parameter trust 
(§6); §5a knobs + defaults; §8 properties (symptom + severity); §9 disclaimed 
properties + false friends; §11a non-findings; §13 dispositions. The prose 
remains canonical.


Reply via email to