milamberspace commented on code in PR #6709:
URL: https://github.com/apache/jmeter/pull/6709#discussion_r3344543964


##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,172 @@
+# Apache JMeter — Threat Model (v0 draft)
+
+> Built on Apache JMeter's existing security policy at
+> <https://jmeter.apache.org/security.html>. That page's "Security Model"
+> statements are lifted here verbatim as the *(documented)* core; this
+> document adds the threat-model structure around them (adversary model,
+> in/out scope, properties, known non-findings, triage dispositions).
+
+## §1 Header
+
+- **Project:** Apache JMeter (`apache/jmeter`), `master`, against which this 
draft was written.
+- **Date:** 2026-06-02. **Status:** draft — for Apache JMeter PMC review. 
**Author:** ASF Security team (drafted via the Scovetta threat-model rubric, 
building on JMeter's `security.html`), for PMC ratification.
+- **Version binding:** versioned with the project; a report against version 
*N* is triaged against the model as it stood at *N*.
+- **Reporting cross-reference:** §8-property violations → report privately per 
ASF process (`[email protected]` → `[email protected]`); §3/§9 
findings are closed citing this document and `security.html`.
+- **Provenance legend:** *(documented)* = JMeter's own 
docs/`security.html`/repo; *(maintainer)* = confirmed by a JMeter PMC member 
through this process; *(inferred)* = reasoned from architecture, not yet 
confirmed — each has a matching §14 open question.
+- **Coexistence:** this model is a strict superset of `security.html`; nothing 
there is weakened. `security.html` stays the canonical reporting/policy page 
and should link here for the expanded model.
+- **Draft confidence:** ~10 documented / 0 maintainer / ~26 inferred.
+- **What JMeter is:** Apache JMeter is a Java load-/performance-testing tool. 
A user builds a **test plan** (a `.jmx` file) in the GUI or by hand, then runs 
it — in the GUI, in non-GUI/CLI mode, or distributed across a controller and 
remote engines — to drive load at a *system under test* and collect results. 
Test plans may contain scripting (JSR223/Groovy/BeanShell) and therefore 
arbitrary code. *(documented — README, security.html)*
+
+## §2 Scope and intended use
+
+- **Primary use:** a **user-run tool** — the person running JMeter authors (or 
obtains) the `.jmx`, points it at a target they are authorised to test, and 
runs it locally or across machines they control. *(documented — security.html)*
+- **The user is the trusted operator.** The central design statement: *"The 
purpose of JMeter is to execute the workload specified in the input jmx file, 
which may include arbitrary code"* — so JMeter running the plan it is given is 
the intended behaviour, not an attack. *(documented — security.html)*
+- **Roles** (a tool, but distributed mode introduces a network surface):
+  - **user/operator** — supplies the `.jmx`, runs JMeter. **Trusted.** 
*(documented)*
+  - **distributed remote engine** (`jmeter-server`) — a node that accepts a 
test plan from a controller over RMI and executes it. A **listening network 
surface** in distributed mode. *(documented — distributed testing + 
security-manager guidance)*
+  - **system under test (SUT)** — the target JMeter sends requests to and 
whose responses it parses. JMeter is the *client* here. *(inferred)*
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| Test-plan load + execution (GUI / non-GUI) | open/run a `.jmx`; 
JSR223/Groovy/BeanShell elements | runs arbitrary code **by design** | **In, 
but see §9 — executing the plan is by-design** *(documented)* |
+| Distributed / remote testing | `jmeter-server` RMI controller↔engine | 
network (listens) | **In — the real network boundary** *(documented)* |
+| Protocol client + response processing | HTTP/JDBC/JMS/etc. samplers; 
XPath/JSON/regex extractors | network (egress to SUT); parses responses | **In 
— JMeter as a client parsing SUT responses** *(inferred)* |
+| Report/results generation | listeners, dashboard | filesystem | **In 
(parsing result files)** *(inferred)* |
+| Plugins / properties / functions | `user.properties`, plugins, `__function` 
calls | varies | **In core; third-party plugins out** *(inferred)* |
+| `examples/`, test resources, demos | — | — | **Out** *(see §3)* |
+
+## §3 Out of scope (explicit non-goals)
+
+- **Executing the test plan the user gives it** — including arbitrary 
scripting in that plan. This is the whole purpose of the tool. A report that "a 
`.jmx` / JSR223 element can run code" is **not a vulnerability**; it is the 
documented design. *(documented — security.html)*
+- **Isolating untrusted `.jmx` files** — explicitly delegated to the user: 
*"If you want to use JMeter to evaluate untrusted jmx files, it is up to you to 
provide the required isolation."* *(documented — security.html)*
+- **Attackers who already control the machine JMeter runs on, its 
`user.properties`, its plugins, or the controller in a distributed run.** 
Operator-trusted. *(inferred)*
+- **The security of the system under test.** JMeter drives load at it; 
defending the SUT is not JMeter's job. *(inferred)*
+- **`examples/`, demo/test resources.** *(inferred)*
+
+## §4 Trust boundaries and data flow
+
+- **The `.jmx` is NOT a trust boundary — it is trusted input by design** (§3). 
The user vouches for the plan they run. *(documented)*
+- **The distributed-testing RMI surface IS a trust boundary.** `jmeter-server` 
accepts a serialized test plan + commands from a controller over RMI; an 
attacker who can reach that port (or MITM it) without the protections could get 
the engine to execute a plan — i.e. code execution on the remote host. The 
documented defense: *"when JMeter is used in distributed environment, we 
recommend setting up the security manager in order to avoid any execution of 
malicious code on the distributed architecture"*, plus RMI-over-SSL with 
keystore/client-auth for the controller↔engine channel. *(documented — 
security.html + distributed-testing docs; SSL specifics inferred)*
+- **The SUT→JMeter response path is a (softer) boundary:** if a user is 
induced to test a hostile server, that server's responses are parsed by 
JMeter's extractors (XML/XPath → XXE, regex → ReDoS, large responses → memory). 
Whether this is in-model depends on how adversarial the SUT is assumed to be 
(see §14). *(inferred)*
+- **Reachability precondition:** a finding is **in-model** if it is reachable 
(a) by a network party against the distributed-RMI surface under the 
documented/default protections, or (b) from a malicious SUT's responses 
(subject to §14), or (c) pre-execution while merely *opening* a file the user 
did not intend to be executable. Anything that requires the user to run a 
`.jmx` they chose to run is `OUT-OF-MODEL`/`BY-DESIGN`. *(inferred)*
+
+## §5 Assumptions about the environment
+
+- **Runtime:** JVM; runs as a desktop GUI app, a CLI process, or 
`jmeter-server` remote engine. *(documented — README)*
+- **The user controls the host, the `.jmx`, `user.properties`, installed 
plugins, and (in distributed mode) the controller and engines.** *(inferred)*
+- **Java Security Manager** is the documented isolation mechanism for 
distributed/untrusted-plan scenarios — but note it is the *user's* to 
configure, and the platform Security Manager is deprecated in modern JDKs (a 
§14 question on the forward story). *(documented that it is recommended; the 
deprecation caveat inferred)*
+- **Negative side-effects inventory** (inferred — wave-1/2 target): JMeter 
makes outbound network requests to the SUT by design; in distributed mode it 
listens for RMI; it reads/writes test plans, results, and properties on the 
local filesystem; it executes user-supplied scripting. *(inferred)*
+
+## §5a Build-time and configuration variants
+
+Security-relevant configuration *(documented unless noted):*
+
+- **Distributed RMI security** — the controller↔engine channel: RMI-over-SSL 
with a keystore and client auth (default on in recent versions?), plus the 
recommended **Security Manager** policy on engines. Confirm the current 
defaults. *(documented that the security manager is recommended; SSL default 
inferred)*
+- **`jmeter-server` bind / exposure** — what interface the remote engine binds 
to by default, and whether it requires the SSL keystore to start. *(inferred)*
+- **Scripting elements** (JSR223/Groovy/BeanShell, `__groovy`/`__BeanShell` 
functions) — always available; gated only by who controls the `.jmx` (the 
user). *(documented design)*
+
+**Insecure-default check:** if `jmeter-server` ships accepting RMI connections 
without SSL/auth by default, a report against that default is `VALID`; if 
SSL/keystore is required by default, an unprotected deployment is 
`OUT-OF-MODEL: non-default-build`. Wave-1 question (§14). (Cf. CVE-2019-0187, 
the historical RMI-without-SSL issue.)
+
+## §6 Assumptions about inputs
+
+Per-surface trust table *(all inferred unless noted):*
+
+| Surface | Input | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| `.jmx` test plan (open/run) | plan XML + embedded scripts | **no — trusted 
by design**; **yes only if the user runs an untrusted plan**, which they must 
isolate | don't open/run untrusted `.jmx` without OS/JVM isolation |
+| Distributed RMI (`jmeter-server`) | controller commands + serialized plan | 
**yes (network), if the channel is unprotected** | RMI-over-SSL + keystore + 
Security Manager on engines |
+| SUT responses | HTTP/JDBC/etc. response bodies | **yes if the SUT is 
hostile** | test only systems you trust/own, or treat responses as untrusted |
+| `user.properties` / plugins | local config | no — operator-trusted | vet 
plugins |
+| Result/JTL files (re-opened) | results to render | **yes if a result file is 
from an untrusted source** | don't open untrusted result files |
+
+- **Size/shape/rate:** response/result-file size handling and recursion 
(XML/regex) bounds are open (see §8). *(inferred)*
+
+## §7 Adversary model
+
+- **Distributed-mode network attacker** — can reach a `jmeter-server` RMI port 
or MITM the controller↔engine link; goal: code execution on a remote engine. 
The primary in-model adversary. *(documented surface; framing inferred)*
+- **Malicious-`.jmx` social-engineering** — tricks a user into 
*opening/running* a hostile plan. JMeter's stance: this executes by design; 
isolation is the user's responsibility. So this is an *acknowledged, 
disclaimed* threat, not a defended one. *(documented — security.html)*
+- **Malicious SUT** — a target server returning hostile responses to exploit 
JMeter's response parsing. In-model only if the PMC assumes the SUT can be 
adversarial (see §14). *(inferred)*
+- **Out of scope:** anyone with control of the JMeter host, the controller, 
`user.properties`, or installed plugins. *(inferred)*
+
+## §8 Security properties the project provides
+
+*(Distributed-mode protection is documented-as-recommended; the guarantees 
below are for PMC confirmation.)*
+
+- **Distributed-mode isolation (when configured).** With RMI-over-SSL + 
keystore/client-auth and the recommended Security Manager, a network party 
cannot drive a remote engine to execute code. *Violation symptom:* remote code 
execution on a `jmeter-server` engine by an unauthenticated/MITM network party 
under the documented protections. *Severity:* security-critical. *(documented 
that the protections are recommended; that they hold is the claim to confirm)*
+- **No unintended code execution from *opening* a non-executed file** — 
opening a result/JTL file, or loading a `.jmx` into the GUI without running it, 
should not by itself be a path to code execution *beyond what `security.html` 
already discloses for `.jmx`*. (security.html says even *opening* a `.jmx` "may 
in some cases trigger code execution" — so the in-model line is about result 
files and unexpected triggers.) *Violation symptom:* code execution from 
opening a file the user did not run. *Severity:* security-critical. *(inferred 
— needs the PMC to draw this line precisely)*
+- **Safe response handling — UNSPECIFIED.** Whether JMeter's extractors are 
hardened against hostile SUT responses (XXE, ReDoS, decompression/size bombs) 
is open. *(inferred)*

Review Comment:
   test



##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,172 @@
+# Apache JMeter — Threat Model (v0 draft)
+
+> Built on Apache JMeter's existing security policy at
+> <https://jmeter.apache.org/security.html>. That page's "Security Model"
+> statements are lifted here verbatim as the *(documented)* core; this
+> document adds the threat-model structure around them (adversary model,
+> in/out scope, properties, known non-findings, triage dispositions).
+
+## §1 Header
+
+- **Project:** Apache JMeter (`apache/jmeter`), `master`, against which this 
draft was written.
+- **Date:** 2026-06-02. **Status:** draft — for Apache JMeter PMC review. 
**Author:** ASF Security team (drafted via the Scovetta threat-model rubric, 
building on JMeter's `security.html`), for PMC ratification.
+- **Version binding:** versioned with the project; a report against version 
*N* is triaged against the model as it stood at *N*.
+- **Reporting cross-reference:** §8-property violations → report privately per 
ASF process (`[email protected]` → `[email protected]`); §3/§9 
findings are closed citing this document and `security.html`.
+- **Provenance legend:** *(documented)* = JMeter's own 
docs/`security.html`/repo; *(maintainer)* = confirmed by a JMeter PMC member 
through this process; *(inferred)* = reasoned from architecture, not yet 
confirmed — each has a matching §14 open question.
+- **Coexistence:** this model is a strict superset of `security.html`; nothing 
there is weakened. `security.html` stays the canonical reporting/policy page 
and should link here for the expanded model.
+- **Draft confidence:** ~10 documented / 0 maintainer / ~26 inferred.
+- **What JMeter is:** Apache JMeter is a Java load-/performance-testing tool. 
A user builds a **test plan** (a `.jmx` file) in the GUI or by hand, then runs 
it — in the GUI, in non-GUI/CLI mode, or distributed across a controller and 
remote engines — to drive load at a *system under test* and collect results. 
Test plans may contain scripting (JSR223/Groovy/BeanShell) and therefore 
arbitrary code. *(documented — README, security.html)*
+
+## §2 Scope and intended use
+
+- **Primary use:** a **user-run tool** — the person running JMeter authors (or 
obtains) the `.jmx`, points it at a target they are authorised to test, and 
runs it locally or across machines they control. *(documented — security.html)*
+- **The user is the trusted operator.** The central design statement: *"The 
purpose of JMeter is to execute the workload specified in the input jmx file, 
which may include arbitrary code"* — so JMeter running the plan it is given is 
the intended behaviour, not an attack. *(documented — security.html)*
+- **Roles** (a tool, but distributed mode introduces a network surface):
+  - **user/operator** — supplies the `.jmx`, runs JMeter. **Trusted.** 
*(documented)*
+  - **distributed remote engine** (`jmeter-server`) — a node that accepts a 
test plan from a controller over RMI and executes it. A **listening network 
surface** in distributed mode. *(documented — distributed testing + 
security-manager guidance)*
+  - **system under test (SUT)** — the target JMeter sends requests to and 
whose responses it parses. JMeter is the *client* here. *(inferred)*
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| Test-plan load + execution (GUI / non-GUI) | open/run a `.jmx`; 
JSR223/Groovy/BeanShell elements | runs arbitrary code **by design** | **In, 
but see §9 — executing the plan is by-design** *(documented)* |
+| Distributed / remote testing | `jmeter-server` RMI controller↔engine | 
network (listens) | **In — the real network boundary** *(documented)* |
+| Protocol client + response processing | HTTP/JDBC/JMS/etc. samplers; 
XPath/JSON/regex extractors | network (egress to SUT); parses responses | **In 
— JMeter as a client parsing SUT responses** *(inferred)* |
+| Report/results generation | listeners, dashboard | filesystem | **In 
(parsing result files)** *(inferred)* |
+| Plugins / properties / functions | `user.properties`, plugins, `__function` 
calls | varies | **In core; third-party plugins out** *(inferred)* |
+| `examples/`, test resources, demos | — | — | **Out** *(see §3)* |
+
+## §3 Out of scope (explicit non-goals)
+
+- **Executing the test plan the user gives it** — including arbitrary 
scripting in that plan. This is the whole purpose of the tool. A report that "a 
`.jmx` / JSR223 element can run code" is **not a vulnerability**; it is the 
documented design. *(documented — security.html)*
+- **Isolating untrusted `.jmx` files** — explicitly delegated to the user: 
*"If you want to use JMeter to evaluate untrusted jmx files, it is up to you to 
provide the required isolation."* *(documented — security.html)*
+- **Attackers who already control the machine JMeter runs on, its 
`user.properties`, its plugins, or the controller in a distributed run.** 
Operator-trusted. *(inferred)*
+- **The security of the system under test.** JMeter drives load at it; 
defending the SUT is not JMeter's job. *(inferred)*
+- **`examples/`, demo/test resources.** *(inferred)*
+
+## §4 Trust boundaries and data flow
+
+- **The `.jmx` is NOT a trust boundary — it is trusted input by design** (§3). 
The user vouches for the plan they run. *(documented)*
+- **The distributed-testing RMI surface IS a trust boundary.** `jmeter-server` 
accepts a serialized test plan + commands from a controller over RMI; an 
attacker who can reach that port (or MITM it) without the protections could get 
the engine to execute a plan — i.e. code execution on the remote host. The 
documented defense: *"when JMeter is used in distributed environment, we 
recommend setting up the security manager in order to avoid any execution of 
malicious code on the distributed architecture"*, plus RMI-over-SSL with 
keystore/client-auth for the controller↔engine channel. *(documented — 
security.html + distributed-testing docs; SSL specifics inferred)*
+- **The SUT→JMeter response path is a (softer) boundary:** if a user is 
induced to test a hostile server, that server's responses are parsed by 
JMeter's extractors (XML/XPath → XXE, regex → ReDoS, large responses → memory). 
Whether this is in-model depends on how adversarial the SUT is assumed to be 
(see §14). *(inferred)*
+- **Reachability precondition:** a finding is **in-model** if it is reachable 
(a) by a network party against the distributed-RMI surface under the 
documented/default protections, or (b) from a malicious SUT's responses 
(subject to §14), or (c) pre-execution while merely *opening* a file the user 
did not intend to be executable. Anything that requires the user to run a 
`.jmx` they chose to run is `OUT-OF-MODEL`/`BY-DESIGN`. *(inferred)*
+
+## §5 Assumptions about the environment
+
+- **Runtime:** JVM; runs as a desktop GUI app, a CLI process, or 
`jmeter-server` remote engine. *(documented — README)*
+- **The user controls the host, the `.jmx`, `user.properties`, installed 
plugins, and (in distributed mode) the controller and engines.** *(inferred)*
+- **Java Security Manager** is the documented isolation mechanism for 
distributed/untrusted-plan scenarios — but note it is the *user's* to 
configure, and the platform Security Manager is deprecated in modern JDKs (a 
§14 question on the forward story). *(documented that it is recommended; the 
deprecation caveat inferred)*
+- **Negative side-effects inventory** (inferred — wave-1/2 target): JMeter 
makes outbound network requests to the SUT by design; in distributed mode it 
listens for RMI; it reads/writes test plans, results, and properties on the 
local filesystem; it executes user-supplied scripting. *(inferred)*
+
+## §5a Build-time and configuration variants
+
+Security-relevant configuration *(documented unless noted):*
+
+- **Distributed RMI security** — the controller↔engine channel: RMI-over-SSL 
with a keystore and client auth (default on in recent versions?), plus the 
recommended **Security Manager** policy on engines. Confirm the current 
defaults. *(documented that the security manager is recommended; SSL default 
inferred)*
+- **`jmeter-server` bind / exposure** — what interface the remote engine binds 
to by default, and whether it requires the SSL keystore to start. *(inferred)*
+- **Scripting elements** (JSR223/Groovy/BeanShell, `__groovy`/`__BeanShell` 
functions) — always available; gated only by who controls the `.jmx` (the 
user). *(documented design)*
+
+**Insecure-default check:** if `jmeter-server` ships accepting RMI connections 
without SSL/auth by default, a report against that default is `VALID`; if 
SSL/keystore is required by default, an unprotected deployment is 
`OUT-OF-MODEL: non-default-build`. Wave-1 question (§14). (Cf. CVE-2019-0187, 
the historical RMI-without-SSL issue.)
+
+## §6 Assumptions about inputs
+
+Per-surface trust table *(all inferred unless noted):*
+
+| Surface | Input | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| `.jmx` test plan (open/run) | plan XML + embedded scripts | **no — trusted 
by design**; **yes only if the user runs an untrusted plan**, which they must 
isolate | don't open/run untrusted `.jmx` without OS/JVM isolation |
+| Distributed RMI (`jmeter-server`) | controller commands + serialized plan | 
**yes (network), if the channel is unprotected** | RMI-over-SSL + keystore + 
Security Manager on engines |
+| SUT responses | HTTP/JDBC/etc. response bodies | **yes if the SUT is 
hostile** | test only systems you trust/own, or treat responses as untrusted |
+| `user.properties` / plugins | local config | no — operator-trusted | vet 
plugins |
+| Result/JTL files (re-opened) | results to render | **yes if a result file is 
from an untrusted source** | don't open untrusted result files |
+
+- **Size/shape/rate:** response/result-file size handling and recursion 
(XML/regex) bounds are open (see §8). *(inferred)*
+
+## §7 Adversary model
+
+- **Distributed-mode network attacker** — can reach a `jmeter-server` RMI port 
or MITM the controller↔engine link; goal: code execution on a remote engine. 
The primary in-model adversary. *(documented surface; framing inferred)*
+- **Malicious-`.jmx` social-engineering** — tricks a user into 
*opening/running* a hostile plan. JMeter's stance: this executes by design; 
isolation is the user's responsibility. So this is an *acknowledged, 
disclaimed* threat, not a defended one. *(documented — security.html)*
+- **Malicious SUT** — a target server returning hostile responses to exploit 
JMeter's response parsing. In-model only if the PMC assumes the SUT can be 
adversarial (see §14). *(inferred)*
+- **Out of scope:** anyone with control of the JMeter host, the controller, 
`user.properties`, or installed plugins. *(inferred)*
+
+## §8 Security properties the project provides
+
+*(Distributed-mode protection is documented-as-recommended; the guarantees 
below are for PMC confirmation.)*
+
+- **Distributed-mode isolation (when configured).** With RMI-over-SSL + 
keystore/client-auth and the recommended Security Manager, a network party 
cannot drive a remote engine to execute code. *Violation symptom:* remote code 
execution on a `jmeter-server` engine by an unauthenticated/MITM network party 
under the documented protections. *Severity:* security-critical. *(documented 
that the protections are recommended; that they hold is the claim to confirm)*
+- **No unintended code execution from *opening* a non-executed file** — 
opening a result/JTL file, or loading a `.jmx` into the GUI without running it, 
should not by itself be a path to code execution *beyond what `security.html` 
already discloses for `.jmx`*. (security.html says even *opening* a `.jmx` "may 
in some cases trigger code execution" — so the in-model line is about result 
files and unexpected triggers.) *Violation symptom:* code execution from 
opening a file the user did not run. *Severity:* security-critical. *(inferred 
— needs the PMC to draw this line precisely)*
+- **Safe response handling — UNSPECIFIED.** Whether JMeter's extractors are 
hardened against hostile SUT responses (XXE, ReDoS, decompression/size bombs) 
is open. *(inferred)*

Review Comment:
   > Frankly, I am not sure if we would like to open "we consider a 
vulnerability if a malicious SUT can trick JMeter" box.
   
   I agree — we should **not** open that box in the threat model.
   
   The reasoning: JMeter's own documentation says "test only systems you are 
authorised to test", which means the SUT is, by definition, under the 
operator's control or trust. A "malicious SUT" is therefore out of scope in the 
same way that an attacker who already controls the JMeter host is out of scope.
   
   In practice, hardening the response parsers (XXE in the XPath Extractor, 
response-size limits against decompression bombs, ReDoS exposure in regex 
extractors) is still worth doing, but it should be classified as 
`VALID-HARDENING` discovered through an internal audit — not as an in-model 
vulnerability that external reporters can claim via this threat model.
   
   Keeping "safe response handling — UNSPECIFIED" in §8 with a note 
"best-effort, not a claimed property" seems the right balance: we do not 
promise full robustness against a hostile SUT, and we do not invite reporters 
to submit XXE/ReDoS findings as security vulnerabilities.



##########
THREAT_MODEL.md:
##########
@@ -0,0 +1,172 @@
+# Apache JMeter — Threat Model (v0 draft)
+
+> Built on Apache JMeter's existing security policy at
+> <https://jmeter.apache.org/security.html>. That page's "Security Model"
+> statements are lifted here verbatim as the *(documented)* core; this
+> document adds the threat-model structure around them (adversary model,
+> in/out scope, properties, known non-findings, triage dispositions).
+
+## §1 Header
+
+- **Project:** Apache JMeter (`apache/jmeter`), `master`, against which this 
draft was written.
+- **Date:** 2026-06-02. **Status:** draft — for Apache JMeter PMC review. 
**Author:** ASF Security team (drafted via the Scovetta threat-model rubric, 
building on JMeter's `security.html`), for PMC ratification.
+- **Version binding:** versioned with the project; a report against version 
*N* is triaged against the model as it stood at *N*.
+- **Reporting cross-reference:** §8-property violations → report privately per 
ASF process (`[email protected]` → `[email protected]`); §3/§9 
findings are closed citing this document and `security.html`.
+- **Provenance legend:** *(documented)* = JMeter's own 
docs/`security.html`/repo; *(maintainer)* = confirmed by a JMeter PMC member 
through this process; *(inferred)* = reasoned from architecture, not yet 
confirmed — each has a matching §14 open question.
+- **Coexistence:** this model is a strict superset of `security.html`; nothing 
there is weakened. `security.html` stays the canonical reporting/policy page 
and should link here for the expanded model.
+- **Draft confidence:** ~10 documented / 0 maintainer / ~26 inferred.
+- **What JMeter is:** Apache JMeter is a Java load-/performance-testing tool. 
A user builds a **test plan** (a `.jmx` file) in the GUI or by hand, then runs 
it — in the GUI, in non-GUI/CLI mode, or distributed across a controller and 
remote engines — to drive load at a *system under test* and collect results. 
Test plans may contain scripting (JSR223/Groovy/BeanShell) and therefore 
arbitrary code. *(documented — README, security.html)*
+
+## §2 Scope and intended use
+
+- **Primary use:** a **user-run tool** — the person running JMeter authors (or 
obtains) the `.jmx`, points it at a target they are authorised to test, and 
runs it locally or across machines they control. *(documented — security.html)*
+- **The user is the trusted operator.** The central design statement: *"The 
purpose of JMeter is to execute the workload specified in the input jmx file, 
which may include arbitrary code"* — so JMeter running the plan it is given is 
the intended behaviour, not an attack. *(documented — security.html)*
+- **Roles** (a tool, but distributed mode introduces a network surface):
+  - **user/operator** — supplies the `.jmx`, runs JMeter. **Trusted.** 
*(documented)*
+  - **distributed remote engine** (`jmeter-server`) — a node that accepts a 
test plan from a controller over RMI and executes it. A **listening network 
surface** in distributed mode. *(documented — distributed testing + 
security-manager guidance)*
+  - **system under test (SUT)** — the target JMeter sends requests to and 
whose responses it parses. JMeter is the *client* here. *(inferred)*
+
+**Component-family table:**
+
+| Family | Entry point | Touches outside process | In model? |
+| --- | --- | --- | --- |
+| Test-plan load + execution (GUI / non-GUI) | open/run a `.jmx`; 
JSR223/Groovy/BeanShell elements | runs arbitrary code **by design** | **In, 
but see §9 — executing the plan is by-design** *(documented)* |
+| Distributed / remote testing | `jmeter-server` RMI controller↔engine | 
network (listens) | **In — the real network boundary** *(documented)* |
+| Protocol client + response processing | HTTP/JDBC/JMS/etc. samplers; 
XPath/JSON/regex extractors | network (egress to SUT); parses responses | **In 
— JMeter as a client parsing SUT responses** *(inferred)* |
+| Report/results generation | listeners, dashboard | filesystem | **In 
(parsing result files)** *(inferred)* |
+| Plugins / properties / functions | `user.properties`, plugins, `__function` 
calls | varies | **In core; third-party plugins out** *(inferred)* |
+| `examples/`, test resources, demos | — | — | **Out** *(see §3)* |
+
+## §3 Out of scope (explicit non-goals)
+
+- **Executing the test plan the user gives it** — including arbitrary 
scripting in that plan. This is the whole purpose of the tool. A report that "a 
`.jmx` / JSR223 element can run code" is **not a vulnerability**; it is the 
documented design. *(documented — security.html)*
+- **Isolating untrusted `.jmx` files** — explicitly delegated to the user: 
*"If you want to use JMeter to evaluate untrusted jmx files, it is up to you to 
provide the required isolation."* *(documented — security.html)*
+- **Attackers who already control the machine JMeter runs on, its 
`user.properties`, its plugins, or the controller in a distributed run.** 
Operator-trusted. *(inferred)*
+- **The security of the system under test.** JMeter drives load at it; 
defending the SUT is not JMeter's job. *(inferred)*
+- **`examples/`, demo/test resources.** *(inferred)*
+
+## §4 Trust boundaries and data flow
+
+- **The `.jmx` is NOT a trust boundary — it is trusted input by design** (§3). 
The user vouches for the plan they run. *(documented)*
+- **The distributed-testing RMI surface IS a trust boundary.** `jmeter-server` 
accepts a serialized test plan + commands from a controller over RMI; an 
attacker who can reach that port (or MITM it) without the protections could get 
the engine to execute a plan — i.e. code execution on the remote host. The 
documented defense: *"when JMeter is used in distributed environment, we 
recommend setting up the security manager in order to avoid any execution of 
malicious code on the distributed architecture"*, plus RMI-over-SSL with 
keystore/client-auth for the controller↔engine channel. *(documented — 
security.html + distributed-testing docs; SSL specifics inferred)*
+- **The SUT→JMeter response path is a (softer) boundary:** if a user is 
induced to test a hostile server, that server's responses are parsed by 
JMeter's extractors (XML/XPath → XXE, regex → ReDoS, large responses → memory). 
Whether this is in-model depends on how adversarial the SUT is assumed to be 
(see §14). *(inferred)*
+- **Reachability precondition:** a finding is **in-model** if it is reachable 
(a) by a network party against the distributed-RMI surface under the 
documented/default protections, or (b) from a malicious SUT's responses 
(subject to §14), or (c) pre-execution while merely *opening* a file the user 
did not intend to be executable. Anything that requires the user to run a 
`.jmx` they chose to run is `OUT-OF-MODEL`/`BY-DESIGN`. *(inferred)*
+
+## §5 Assumptions about the environment
+
+- **Runtime:** JVM; runs as a desktop GUI app, a CLI process, or 
`jmeter-server` remote engine. *(documented — README)*
+- **The user controls the host, the `.jmx`, `user.properties`, installed 
plugins, and (in distributed mode) the controller and engines.** *(inferred)*
+- **Java Security Manager** is the documented isolation mechanism for 
distributed/untrusted-plan scenarios — but note it is the *user's* to 
configure, and the platform Security Manager is deprecated in modern JDKs (a 
§14 question on the forward story). *(documented that it is recommended; the 
deprecation caveat inferred)*
+- **Negative side-effects inventory** (inferred — wave-1/2 target): JMeter 
makes outbound network requests to the SUT by design; in distributed mode it 
listens for RMI; it reads/writes test plans, results, and properties on the 
local filesystem; it executes user-supplied scripting. *(inferred)*
+
+## §5a Build-time and configuration variants
+
+Security-relevant configuration *(documented unless noted):*
+
+- **Distributed RMI security** — the controller↔engine channel: RMI-over-SSL 
with a keystore and client auth (default on in recent versions?), plus the 
recommended **Security Manager** policy on engines. Confirm the current 
defaults. *(documented that the security manager is recommended; SSL default 
inferred)*
+- **`jmeter-server` bind / exposure** — what interface the remote engine binds 
to by default, and whether it requires the SSL keystore to start. *(inferred)*
+- **Scripting elements** (JSR223/Groovy/BeanShell, `__groovy`/`__BeanShell` 
functions) — always available; gated only by who controls the `.jmx` (the 
user). *(documented design)*
+
+**Insecure-default check:** if `jmeter-server` ships accepting RMI connections 
without SSL/auth by default, a report against that default is `VALID`; if 
SSL/keystore is required by default, an unprotected deployment is 
`OUT-OF-MODEL: non-default-build`. Wave-1 question (§14). (Cf. CVE-2019-0187, 
the historical RMI-without-SSL issue.)
+
+## §6 Assumptions about inputs
+
+Per-surface trust table *(all inferred unless noted):*
+
+| Surface | Input | Attacker-controllable? | Caller/operator must enforce |
+| --- | --- | --- | --- |
+| `.jmx` test plan (open/run) | plan XML + embedded scripts | **no — trusted 
by design**; **yes only if the user runs an untrusted plan**, which they must 
isolate | don't open/run untrusted `.jmx` without OS/JVM isolation |
+| Distributed RMI (`jmeter-server`) | controller commands + serialized plan | 
**yes (network), if the channel is unprotected** | RMI-over-SSL + keystore + 
Security Manager on engines |
+| SUT responses | HTTP/JDBC/etc. response bodies | **yes if the SUT is 
hostile** | test only systems you trust/own, or treat responses as untrusted |
+| `user.properties` / plugins | local config | no — operator-trusted | vet 
plugins |
+| Result/JTL files (re-opened) | results to render | **yes if a result file is 
from an untrusted source** | don't open untrusted result files |
+
+- **Size/shape/rate:** response/result-file size handling and recursion 
(XML/regex) bounds are open (see §8). *(inferred)*
+
+## §7 Adversary model
+
+- **Distributed-mode network attacker** — can reach a `jmeter-server` RMI port 
or MITM the controller↔engine link; goal: code execution on a remote engine. 
The primary in-model adversary. *(documented surface; framing inferred)*
+- **Malicious-`.jmx` social-engineering** — tricks a user into 
*opening/running* a hostile plan. JMeter's stance: this executes by design; 
isolation is the user's responsibility. So this is an *acknowledged, 
disclaimed* threat, not a defended one. *(documented — security.html)*
+- **Malicious SUT** — a target server returning hostile responses to exploit 
JMeter's response parsing. In-model only if the PMC assumes the SUT can be 
adversarial (see §14). *(inferred)*
+- **Out of scope:** anyone with control of the JMeter host, the controller, 
`user.properties`, or installed plugins. *(inferred)*
+
+## §8 Security properties the project provides
+
+*(Distributed-mode protection is documented-as-recommended; the guarantees 
below are for PMC confirmation.)*
+
+- **Distributed-mode isolation (when configured).** With RMI-over-SSL + 
keystore/client-auth and the recommended Security Manager, a network party 
cannot drive a remote engine to execute code. *Violation symptom:* remote code 
execution on a `jmeter-server` engine by an unauthenticated/MITM network party 
under the documented protections. *Severity:* security-critical. *(documented 
that the protections are recommended; that they hold is the claim to confirm)*
+- **No unintended code execution from *opening* a non-executed file** — 
opening a result/JTL file, or loading a `.jmx` into the GUI without running it, 
should not by itself be a path to code execution *beyond what `security.html` 
already discloses for `.jmx`*. (security.html says even *opening* a `.jmx` "may 
in some cases trigger code execution" — so the in-model line is about result 
files and unexpected triggers.) *Violation symptom:* code execution from 
opening a file the user did not run. *Severity:* security-critical. *(inferred 
— needs the PMC to draw this line precisely)*
+- **Safe response handling — UNSPECIFIED.** Whether JMeter's extractors are 
hardened against hostile SUT responses (XXE, ReDoS, decompression/size bombs) 
is open. *(inferred)*
+
+## §9 Security properties the project does *not* provide
+
+- **JMeter does not isolate or sandbox the test plan it runs.** *"The JMeter 
security model assumes you trust jmx input files."* Running a `.jmx` runs its 
code, including scripting. *(documented — security.html)* **This is the single 
most important statement for triage.**
+- **JMeter does not protect a user who opens/runs an untrusted `.jmx`** — *"it 
is up to you to provide the required isolation."* *(documented)*
+- **JMeter does not defend the system under test**, and does not guarantee its 
own response-parsing is hardened against a *hostile* SUT unless the PMC says so 
(§14). *(inferred)*
+- **The Security Manager is the user's to configure** (and is JDK-deprecated) 
— JMeter does not impose isolation on distributed engines automatically beyond 
the documented recommendation. *(documented recommendation; deprecation 
inferred)*
+- **False friend:** loading a `.jmx` in the GUI is *not* a safe "preview" — 
opening it "may in some cases trigger code execution". *(documented)*
+- **Well-known classes left to the caller:** untrusted-deserialization / RMI 
attacks on distributed mode (defended by SSL+SecurityManager, if configured), 
and arbitrary code execution via scripting elements in any plan (by-design). 
*(documented/inferred)*
+
+## §10 Downstream responsibilities (the user/operator)
+
+- **Only open and run `.jmx` files you trust**; isolate (separate OS user / 
container / VM) if you must evaluate an untrusted plan. *(documented)*
+- **For distributed testing, enable RMI-over-SSL with a keystore + client 
auth, and configure the Security Manager on engines**; do not expose 
`jmeter-server` on an untrusted network. *(documented recommendation)*
+- **Only point JMeter at systems you are authorised to test**, and treat 
responses from untrusted targets as potentially hostile to the parsers. 
*(inferred)*
+- **Vet third-party plugins** before installing. *(inferred)*
+- **Don't open untrusted result/JTL files.** *(inferred)*
+
+## §11 Known misuse patterns
+
+*(Draft one-liners — expand before publishing.)*
+
+- Running a `.jmx` obtained from an untrusted source without isolation. 
*(documented as the user's risk)*
+- Exposing `jmeter-server` (RMI) on an untrusted network without 
SSL/Security-Manager. *(documented surface)*
+- Treating "open in GUI" as a safe way to inspect an untrusted plan. 
*(documented)*
+- Load-testing a third party's system without authorisation (also a legal 
issue, not just security). *(inferred)*
+
+## §11a Known non-findings (recurring false positives)
+
+*(Seed list — the highest-leverage scan-suppression input; the `.jmx` items 
are documented.)*
+
+- "A `.jmx` / JSR223 / BeanShell element can execute arbitrary code" — 
**by-design**; JMeter executes the plan it is given (§3/§9, security.html). 
`BY-DESIGN`, not a finding.
+- "Opening a `.jmx` triggers code execution" — documented in the security 
model; the user must trust/isolate plans. `BY-DESIGN`.
+- "Scripting/reflection/`Runtime.exec` present in the codebase" — needed to 
execute test plans; reachable only via a trusted plan. `KNOWN-NON-FINDING` 
unless reachable from the distributed-RMI surface or a non-executed file.
+- "RMI deserialization in distributed mode" — `VALID` only if it works 
*without* the documented SSL/Security-Manager protections; otherwise 
`OUT-OF-MODEL: non-default-build` (cf. the post-CVE-2019-0187 posture).
+- "JMeter makes outbound requests / can be pointed anywhere" — by-design; it 
is a load generator (§3).
+
+## §12 Conditions that would change this model
+
+- A change to the distributed-mode RMI/SSL or Security-Manager defaults, or 
the JDK Security Manager's removal forcing a new isolation story. 
*(documented/inferred)*
+- A new way to *open* (not run) a file that triggers execution. *(inferred)*
+- A decision to harden response parsing against hostile SUTs (would move §8 
"response handling" from UNSPECIFIED to a claimed property). *(inferred)*
+- A report that cannot be routed to one §13 disposition → revise the model.
+
+## §13 Triage dispositions
+
+| Disposition | Meaning | Licensed by |
+| --- | --- | --- |
+| `VALID` | Violates a §8 property via an in-scope adversary (RCE on a 
distributed engine despite the documented protections; code exec from *opening* 
a non-run file; confirmed hostile-SUT parser exploit if in scope). | §8, §6, §7 
|
+| `VALID-HARDENING` | No §8 property broken, but a §11 misuse is easy enough 
to harden (e.g. a louder warning on opening untrusted plans, safer parser 
defaults). | §11 |
+| `OUT-OF-MODEL: trusted-input` | Requires the user to run a `.jmx` they chose 
to run, or control of host/controller/properties/plugins. | §3, §6, §7 |
+| `OUT-OF-MODEL: adversary-not-in-scope` | Requires a capability the model 
excludes. | §7 |
+| `OUT-OF-MODEL: unsupported-component` | Lands in `examples/` / demos / 
third-party plugins. | §3 |
+| `OUT-OF-MODEL: non-default-build` | Only manifests with the distributed 
protections disabled or another discouraged §5a setting. | §5a |
+| `BY-DESIGN: property-disclaimed` | Concerns a §9-disclaimed property — above 
all, "JMeter executes the (trusted) test plan, including its code". | §9 |
+| `KNOWN-NON-FINDING` | Matches a §11a entry. | §11a |
+| `MODEL-GAP` | Cannot be cleanly routed — triggers §12. | §12 |
+
+## §14 Open questions for the maintainers
+
+**Wave 1 — confirm the security.html core + distributed defaults:**
+1. Confirm the lifted `security.html` statements are the canonical core: 
trusted `.jmx`, opening may execute, untrusted-plan isolation is the user's job 
— so "`.jmx`/scripting runs code" is `BY-DESIGN`. Proposed: yes. → §3/§9/§11a.
+2. **Distributed mode defaults:** does `jmeter-server` require RMI-over-SSL + 
keystore/client-auth **by default**, and what does it bind to? Is an 
unprotected distributed deployment a `VALID` report or `OUT-OF-MODEL: 
non-default-build`? (Context: CVE-2019-0187.) → §5a/§8.
+3. Confirm `examples/`/demos/third-party plugins are out of scope. → §3.
+
+**Wave 2 — the in-model boundaries:**
+4. **Opening vs running:** where exactly is the line? security.html says even 
*opening* a `.jmx` may execute — so is the in-model guarantee only about 
**result/JTL files** and other non-`.jmx` inputs not triggering execution? → §8.

Review Comment:
   > I would say the line is "opening jmx is safe provided you trust all 
**existing** classes in jmeter distribution". However, if opening a jmx file 
would generate a completely new class and trigger its execution (e.g. somehow 
create a class with some jmx trick), then we probably consider this a 
vulnerability.
   
   I fully agree with this definition. It is precise and useful for triage. 
Worth formalising in the model.
   
   After digging into the code, there is a concrete mechanism today that makes 
the "new class" risk real:
   
   **`JMeterUtils.setupXStreamSecurityPolicy()` is effectively a no-op.**
   
   ```java
   xstream.addPermission(NoTypePermission.NONE);  // deny all...
   xstream.addPermission(AnyTypePermission.ANY);  // ...then allow ALL
   ```
   
   The code even carries a 12-year-old comment: `// TODO : How much are we 
concerned by CVE-2013-7285`. With `AnyTypePermission.ANY`, XStream will 
instantiate **any class on the JVM classpath** during `.jmx` deserialization. 
Any class whose constructor or static initialiser has side effects can execute 
code before the user clicks "Run". This is exactly the "new class triggered by 
a jmx trick" scenario you described.
   
   **The fix:** replace `AnyTypePermission.ANY` with a proper allowlist scoped 
to JMeter's own packages:
   
   ```java
   xstream.addPermission(NoTypePermission.NONE);
   xstream.addPermission(NullPermission.NULL);
   xstream.addPermission(PrimitiveValuePermission.PRIMITIVES);
   xstream.addPermission(ArrayTypePermission.ARRAYS);
   xstream.addPermission(CollectionTypePermission.COLLECTIONS);
   xstream.allowTypesByWildcard(new String[]{
       "org.apache.jmeter.**",
       "org.apache.jorphan.**",
       "java.lang.*",
       "java.util.*",
       "java.net.URL",
   });
   ```
   
   The challenge is ensuring the allowlist is complete enough that existing 
`.jmx` files keep working — it needs integration testing across a range of test 
plans before merging.
   
   **Secondary finding (lower severity):** `BeanShellTestElement.readResolve()` 
calls `init()` which creates a `BeanShellInterpreter` during XStream 
deserialization. It does not compile or execute the script, but it does 
instantiate BeanShell itself on open. Making this lazy (initialise only on the 
first `getBeanShellInterpreter()` call, i.e. at test execution time) would 
shrink that surface.
   
   **Good news:** `JSR223TestElement` is already clean — no `readResolve()`, 
and `getScriptEngine()` is only called from `processFileOrScript()` at test 
execution. Nothing to change there.
   
   Would the PMC consider a follow-up **GitHub Issue** to track the XStream 
allowlist work? Given JMeter 6.0 targets JDK 17+, this is a good moment to 
close a 12-year-old TODO.
   
   ---
   
   **Proposed interim `THREAT_MODEL.md` edits** (to document the current state 
while the fix is tracked separately):
   
   **§8** — refine the second property to make the two sub-cases explicit:
   
   > **No unintended code execution from *opening* a non-executed file** —
   > - *Result/JTL files:* opening for display should not instantiate arbitrary 
classes; this is the stronger guarantee. *(inferred)*
   > - *`.jmx` files:* the in-model guarantee is "opening is safe with respect 
to *existing* JMeter distribution classes". If a crafted `.jmx` triggers 
instantiation of a class *outside* the JMeter distribution (via an XStream 
gadget chain), that is treated as a `VALID` vulnerability. **Current status:** 
the XStream policy (`AnyTypePermission.ANY`) does not yet enforce this boundary 
— a scoped allowlist is a tracked improvement (see §12). *(inferred — PMC 
confirmation requested)*
   
   **§9** — add one bullet after the "False friend" entry:
   
   > **XStream class-loading boundary not yet enforced:** the current 
`setupXStreamSecurityPolicy()` applies `NoTypePermission.NONE` then immediately 
overrides it with `AnyTypePermission.ANY`, allowing instantiation of any JVM 
class during `.jmx` deserialization. Replacing this with a package-scoped 
allowlist (`org.apache.jmeter.**` etc.) is a tracked improvement; until then, 
this boundary is aspirational, not enforced. *(inferred)*
   
   **§11a** — refine the second entry (currently a blanket BY-DESIGN):
   
   > *"Opening a `.jmx` triggers code execution"* — **split into two cases:**
   > - Execution via *existing* JMeter distribution classes during 
deserialization/UI initialisation: `BY-DESIGN`, consistent with `security.html`.
   > - Execution via a class *outside* the JMeter distribution (XStream gadget 
chain, dynamically compiled script triggered before "Run"): `VALID` — this is 
the boundary the model intends to hold.
   
   **§12** — add one condition:
   
   > Merging an XStream package-scoped allowlist (replacing 
`AnyTypePermission.ANY`) — would upgrade the §8 `.jmx`-open guarantee from 
aspirational to enforced, and tighten the §11a triage split above.



-- 
This is an automated message from the Apache Git Service.
To respond to the message, please log on to GitHub and use the
URL above to go to the specific comment.

To unsubscribe, e-mail: [email protected]

For queries about this service, please contact Infrastructure at:
[email protected]

Reply via email to