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).
- Project: Apache JMeter (
apache/jmeter),master, against which this draft was written. - Date: 2026-06-02 (v0); revised 2026-06-04 incorporating the full JMeter PMC review (vlsi, milamberspace). Status: draft v1 — Wave-1/2 questions ratified by the PMC; remaining items are tracked follow-ups (XStream allowlist enforcement;
security.htmlbacklink) flagged in §14. Author: ASF Security team (drafted via the Scovetta threat-model rubric, building on JMeter'ssecurity.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 (
security@apache.org→private@jmeter.apache.org); §3/§9 findings are closed citing this document andsecurity.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.htmlstays the canonical reporting/policy page and should link here for the expanded model (thexdocs/security.xmlbacklink is a tracked follow-up — see §14 Q8). (maintainer) - Draft confidence: ~10 documented / ~20 maintainer / ~6 inferred. The RMI-SSL posture, the open-vs-run line, the XStream policy gap, the Security-Manager/JDK-24 status, the HTTPS-recording-proxy surface, and the SUT scope were all confirmed from JMeter source by the PMC (vlsi, milamberspace) on 2026-06-03/04.
- What JMeter is: Apache JMeter is a Java load-/performance-testing tool. A user builds a test plan (a
.jmxfile) 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)
- 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) - Secondary / dual-use — authorized penetration testing. JMeter is used (and distributed in pentest toolkits) by security professionals for authorized security assessments — rate-limit testing, parameterized enumeration, fuzzing, and custom scenarios via scripting (JSR223/Groovy/BeanShell), parameterized datasets (CSV Dataset Config), and broad protocol support (HTTP/JDBC/LDAP/JMS/…). This is a recognised legitimate use; the operator-trust model is unchanged (the operator is still the trusted party, running a
.jmxthey control against a target they are authorised to test). Conducting such tests without authorization is a legal/ethical violation, already covered by §11. (maintainer, milamberspace 2026-06-04) - 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 and the recording proxy introduce network/trust surfaces):
- 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 guidance) - HTTPS recording proxy (
ProxyControl) — a user-initiated local proxy that MITMs the operator's own HTTPS traffic to record it, backed by a locally-generated Root CA. A local trust boundary (the CA private key on disk). (maintainer, milamberspace 2026-06-04) - system under test (SUT) — the target JMeter sends requests to and whose responses it parses. JMeter is the client here; the SUT is the operator's own/authorised target. (maintainer — SUT scope confirmed 2026-06-04)
- user/operator — supplies the
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) |
| HTTPS recording proxy | ProxyControl (GUI or CLI) |
local filesystem (CA keystore) + MITM on local HTTPS traffic | In — local trust boundary (CA private key) (maintainer) |
| Protocol client + response processing | HTTP/JDBC/JMS/etc. samplers; XPath/JSON/regex extractors | network (egress to SUT); parses responses | In as a client, but hostile-SUT response handling is out of model (§3/§9) (maintainer) |
| 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 (maintainer) |
examples/, test resources, demos |
— | — | Out (maintainer — see §3) |
- 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
.jmxfiles — 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, and robustness against a hostile SUT. JMeter drives load at a target the operator owns/is authorised to test; defending the SUT, and hardening JMeter's parsers against a malicious SUT's crafted responses (XXE/ReDoS/size bombs), is not a claimed property. (maintainer, vlsi + milamberspace 2026-06-04)
- Unauthorized use. Pointing JMeter at systems the operator is not authorised to test (load-testing/pentesting a third party without permission) is a legal/ethical violation, not a JMeter vulnerability (§11). (maintainer, milamberspace 2026-06-04)
examples/, demo/test resources, and third-party plugins. (maintainer, vlsi + milamberspace 2026-06-04)
- The
.jmxis NOT a trust boundary for the code the operator chose to run — it is trusted input by design (§3). The user vouches for the plan they run. The one in-model caveat is the open-time deserialization path (see the open-vs-run boundary below and §8). (documented + maintainer) - The distributed-testing RMI surface IS a trust boundary — and one whose defaults are protective.
jmeter-serveraccepts a serialized test plan + commands from a controller over RMI. Per the PMC's source review (RmiUtils.java): RMI-over-SSL is on by default (server.rmi.ssl.disable=false), the server hard-codessetNeedClientAuth(true)(mutual TLS required), the keystore (rmi_keystore.jks) is not shipped so the engine won't start until the operator generates one (or explicitly disables SSL). So an attacker cannot reach an unprotected engine unless the operator has explicitly opted out withserver.rmi.ssl.disable=true. (maintainer, 2026-06-03 — vlsi + milamberspace, from source) The historical no-SSL RMI-deserialization exposure (CVE-2019-0187) is what these defaults close. (Interface-binding nuance: the RMI port is not restricted to a single interface by default — see §5a.) - The HTTPS-recording-proxy CA private key IS a local trust boundary. In recording mode JMeter generates a local Root CA (
ApacheJMeterTemporaryRootCA.*) stored in a keystore on the operator's machine, dynamically issues per-host certs signed by that CA, and requires the operator to install the CA into their OS/browser trust store. This is analogous to running a private CA on the workstation: if the CA private key is compromised while the CA is still trusted, an attacker could mint certs for any domain accepted silently by the browser (MITM). The defaultproxy.cert.validity=7days limits the exposure window (a sound default; long validity is an opt-in misconfiguration). (maintainer, milamberspace 2026-06-04 — fromProxyControl.java) - The SUT→JMeter response path is not an in-model boundary. The model assumes the tester points JMeter only at systems they own/are authorised to test (§2, §10); a hostile SUT crafting responses to exploit JMeter's extractors (XXE/ReDoS/size bombs) is therefore out of model — robustness there is hardening, not a claimed security property. (maintainer, vlsi + milamberspace 2026-06-04) Classifying it in-model would amount to claiming "JMeter is safe to point at attacker-controlled infrastructure", which is not the intended use case.
- The open-vs-run boundary. Opening/browsing a
.jmxdeserializes the plan and calls getters/setters on the existing control/logic classes JMeter ships — that is safe provided you trust all existing classes in the JMeter distribution. What would be a vulnerability is opening (not running) a file that causes a class outside the JMeter distribution to be instantiated/executed (an XStream gadget chain or a "jmx trick" synthesising and running new code before the user clicks Run). See §8/§9 for the current implementation gap. (maintainer, vlsi + milamberspace 2026-06-03/04) - Reachability precondition: a finding is in-model if it is reachable (a) by a network party against the distributed-RMI surface with the default SSL/mutual-TLS protections in place (i.e. without the operator having set
server.rmi.ssl.disable=true), (b) pre-execution by opening a file that triggers instantiation/execution of a class outside the JMeter distribution (the open-vs-run boundary above), or (c) against the recording-proxy CA-key local boundary. Anything that requires the user to run a.jmxthey chose to run, or a hostile SUT, isOUT-OF-MODEL/BY-DESIGN. (maintainer 2026-06-04)
-
Runtime: JVM (JMeter 6.0 sets JDK 17 as the minimum; users may run on JDK 24+); runs as a desktop GUI app, a CLI process, or
jmeter-serverremote engine. (documented — README; maintainer for the JDK-floor detail) -
The user controls the host, the
.jmx,user.properties, installed plugins, and (in distributed mode) the controller and engines. (inferred) -
Java Security Manager — removed on modern JDKs; NOT the forward defense.
security.htmlhistorically recommends the Security Manager for distributed runs, but it is gone on the JDKs JMeter now targets and cannot be relied on going forward (maintainer, milamberspace 2026-06-04 — the recommendation insecurity.htmlshould be updated):JDK Security Manager status 17 Deprecated for removal (JEP 411) 18–23 Deprecated, still functional (startup warning) 24+ Fully removed (JEP 486) — not available at all Since JMeter 6.0's minimum is JDK 17 and operators may run on JDK 24+, the documented Security-Manager isolation recommendation is not actionable on JDK 24+. The equivalent isolation must now come from outside the JVM (see §9 / §10 for the recommended OS-level replacements). The actual distributed-mode defense is the RMI-over-SSL + mutual-client-auth posture (§4), not the Security Manager.
-
Negative side-effects inventory: JMeter makes outbound network requests to the SUT by design; in distributed mode it listens for RMI; in recording mode it listens on a local proxy port and writes a CA keystore; it reads/writes test plans, results, and properties on the local filesystem; it executes user-supplied scripting. (maintainer / documented)
Security-relevant configuration (documented unless noted):
-
server.rmi.ssl.disable— defaultfalse: RMI-over-SSL is on by default, and the server requires mutual client auth (setNeedClientAuth(true)). The keystore is not shipped, so the engine won't start until the operator provides one or sets this totrue. (maintainer, 2026-06-03) -
jmeter-serverbind interface — not restricted by default. The RMI registry and server socket bind to the addressjava.rmi.server.hostnameresolves to (typically the machine's primary hostname/IP viagetLocalHost()), not a loopback-only or single-interface binding. On a multi-homed or public-IP host this can expose the RMI port on all interfaces. Operators limit exposure withjava.rmi.server.hostname(set to127.0.0.1for loopback-only) and/or perimeter firewall rules — especially important when SSL is disabled. (maintainer, milamberspace 2026-06-04 — corrects the earlier "refuses loopback" wording)Property Default Purpose java.rmi.server.hostname(machine hostname) Which IP the RMI server advertises/binds to; set 127.0.0.1for loopback-onlyserver.rmi.port1099RMI registry port server.rmi.localport(dynamic) Server socket port for the remote engine object; fix it for precise firewall rules -
proxy.cert.validity— default7days (ProxyControl.java): the recording-proxy CA's per-host certs are short-lived by default, limiting MITM-key exposure. A long value (e.g.3650) is an opt-in misconfiguration, not the default. (maintainer, milamberspace 2026-06-04) -
Scripting elements (JSR223/Groovy/BeanShell,
__groovy/__BeanShellfunctions) — always available; gated only by who controls the.jmx(the user). (documented design) -
XStream
.jmxdeserialization policy —setupXStreamSecurityPolicy()currently setsNoTypePermission.NONEthen immediately overrides it withAnyTypePermission.ANY, i.e. the effective policy is a no-op (any JVM class may be instantiated on open). A package-scoped allowlist is the intended fix but is complicated by third-party plugins (see §8/§9/§12). (maintainer, milamberspace + vlsi 2026-06-04)
Insecure-default ruling (resolved): the distributed-mode defaults are secure — an unprotected engine requires the operator to actively set server.rmi.ssl.disable=true. A report that "jmeter-server is unauthenticated / RCE-by-default" is therefore not VALID (the defaults refuse to run without SSL + keystore + client-auth). An exposed engine reached after the operator disabled SSL is OUT-OF-MODEL: non-default-config — note config, not build: it's a runtime property opt-out, no rebuild involved (maintainer, vlsi 2026-06-03). (This closes the CVE-2019-0187 class.)
Per-surface trust table (maintainer unless noted):
| Surface | Input | Attacker-controllable? | Caller/operator must enforce |
|---|---|---|---|
.jmx test plan (run) |
plan XML + embedded scripts | no — trusted by design; yes only if the user runs an untrusted plan, which they must isolate | don't run untrusted .jmx without OS/JVM isolation |
.jmx test plan (open/browse) |
plan XML deserialized via XStream | bounded — safe w.r.t. existing distribution classes; an OUT-OF-distribution class instantiated on open is in-model (currently under-enforced, §8) |
treat opening untrusted .jmx as not fully safe until the XStream allowlist lands |
Distributed RMI (jmeter-server) |
controller commands + serialized plan | no by default (SSL + mutual client-auth required, keystore not shipped → won't start unprotected); yes only if the operator set server.rmi.ssl.disable=true |
keep server.rmi.ssl.disable=false; generate the keystore; restrict the bind interface; never expose an engine after disabling SSL |
| Recording-proxy CA keystore | local CA private key on disk | local — operator-trusted; risk is a stolen key while the CA stays trusted | keep proxy.cert.validity short; remove the CA from the trust store after recording |
| SUT responses | HTTP/JDBC/etc. response bodies | out of model — the tester points JMeter at systems they own/are authorised to test | test only systems you trust/own (hostile-SUT parser robustness is hardening, not a claimed property) |
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 as hardening against a hostile SUT (out of model — see §3/§9). (maintainer)
- Distributed-mode network attacker — can reach a
jmeter-serverRMI port or MITM the controller↔engine link; goal: code execution on a remote engine. The primary in-model adversary, but defeated by the default SSL + mutual-TLS posture (§4/§8). (maintainer) - Crafted-
.jmx-on-open attacker — supplies a.jmxthat, when merely opened, instantiates a class outside the JMeter distribution (XStream gadget chain) to execute code before the user runs the plan. In-model; see §8/§9 for the current enforcement gap. (maintainer, vlsi + milamberspace 2026-06-04) - Recording-proxy CA-key thief — obtains the locally-stored CA private key while the CA is still trusted by the operator's browser/OS, to MITM the operator's traffic. In-model as a local boundary; mitigated by short
proxy.cert.validityand removing the CA after use. (maintainer, milamberspace 2026-06-04) - Malicious-
.jmxsocial-engineering (run) — tricks a user into running a hostile plan. JMeter's stance: this executes by design; isolation is the user's responsibility. An acknowledged, disclaimed threat, not a defended one. (documented — security.html) - Out of scope — malicious SUT. A target server returning hostile responses to exploit JMeter's extractors is not in the adversary model: the tester chooses the target and is expected to test only systems they own/are authorised to test. Parser robustness against a hostile SUT is hardening, not a defended property. (maintainer, vlsi + milamberspace 2026-06-04)
- Out of scope: anyone with control of the JMeter host, the controller,
user.properties, or installed plugins. (inferred)
- Distributed-mode network protection (by default).
jmeter-serverrequires RMI-over-SSL with mutual client auth and won't start without a keystore the operator generates — so a network party cannot drive a remote engine to execute code in the default configuration. Violation symptom: RCE on ajmeter-serverengine by an unauthenticated/MITM network party while SSL is enabled (i.e. withoutserver.rmi.ssl.disable=true). Severity: security-critical. (maintainer, 2026-06-03 — confirmed from source) - No unintended code execution from opening a non-executed file (aspirational; partially enforced).
- Result/JTL files: opening for display should not instantiate arbitrary classes — the stronger guarantee. (inferred)
.jmxfiles: the in-model guarantee is "opening is safe with respect to the existing JMeter distribution classes" (deserialization drives existing control/logic getters/setters, which you trust by trusting the distribution). If a crafted.jmxtriggers instantiation of a class outside the JMeter distribution (an XStream gadget chain, or dynamically-generated/-compiled code) before the user clicks Run, that is treated as aVALIDvulnerability. Current status — not yet enforced:setupXStreamSecurityPolicy()is effectivelyAnyTypePermission.ANY(a no-op, carrying a 12-year-oldCVE-2013-7285TODO), so XStream will instantiate any classpath class during.jmxdeserialization. The boundary is therefore aspirational, not enforced; a package/classloader-scoped allowlist is a tracked improvement (§12), complicated by the need to keep third-party-plugin classes deserializable (a staticorg.apache.jmeter.**allowlist would break plugin test plans — §12). Violation symptom: opening (not running) a.jmx/result file instantiates or executes a class outside the JMeter distribution. Severity: security-critical. (maintainer, vlsi + milamberspace 2026-06-04)
- HTTPS-recording-proxy default exposure window is bounded. The recording proxy issues short-lived per-host certs (
proxy.cert.validity=7days by default), limiting the window in which a stolen CA key is useful. (maintainer, milamberspace 2026-06-04) This is a default-hygiene property, not a guarantee against a stolen-and-still-trusted CA key (§4/§10). - Hostile-SUT response handling is not a claimed property — see §3/§7/§9. The SUT is the tester's own/authorised target; hardening the extractors against a malicious SUT is desirable (
VALID-HARDENINGon an internal-audit track) but not a security guarantee. (maintainer, vlsi + milamberspace 2026-06-04)
- JMeter does not isolate or sandbox the test plan it runs. "The JMeter security model assumes you trust jmx input files." Running a
.jmxruns 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) - XStream class-loading boundary not yet enforced.
setupXStreamSecurityPolicy()appliesNoTypePermission.NONEthen immediately overrides it withAnyTypePermission.ANY, allowing instantiation of any JVM class during.jmxdeserialization. A scoped allowlist (classloader-based, or manifest-declared per plugin, or a targeted gadget denylist — to avoid breaking third-party plugins) is a tracked improvement (§12); until it lands, the §8 "opening is safe given trust in existing classes" property is aspirational, not enforced. A secondary item:BeanShellTestElement.readResolve()instantiates a BeanShell interpreter on open (it does not compile/run the script); making it lazy would shrink the open-time surface. (JSR223TestElementis already clean.) (maintainer, milamberspace + vlsi 2026-06-04) - JMeter does not defend the system under test, and does not claim hardened response-parsing against a hostile SUT. The tester points JMeter at systems they own/are authorised to test; a malicious SUT crafting responses to exploit the extractors (XXE on the XPath Extractor, ReDoS on regex patterns, unbounded response sizes) is out of model —
VALID-HARDENINGat most, not a vulnerability. §8 "safe response handling — best-effort, not a claimed property" is the framing. (maintainer, vlsi + milamberspace 2026-06-04) - No reliance on the Java Security Manager. It is fully removed on JDK 24+ (JEP 486) and not a forward defense; the
security.htmlrecommendation predates that and should be updated. On JDK 24+, the Security Manager is unavailable; OS-level isolation (container, systemd hardening, or dedicated OS user) is the recommended replacement (see §10). Distributed-mode protection comes from RMI-over-SSL + mutual client auth (§4/§8), not the Security Manager. (maintainer, milamberspace 2026-06-04) - JMeter does not guarantee the recording-proxy CA key cannot be misused if stolen while still trusted. The operator must remove the CA from their trust store after recording and keep
proxy.cert.validityshort. (maintainer, milamberspace 2026-06-04) - False friend: loading a
.jmxin the GUI is not a guaranteed-safe "preview" — opening it deserializes the plan and, given the current XStream policy, "may in some cases trigger code execution". (documented + maintainer)
- Only open and run
.jmxfiles you trust; isolate (separate OS user / container / VM) if you must evaluate an untrusted plan. Treat opening an untrusted.jmxas not fully safe until the XStream allowlist lands (§8/§9). (documented + maintainer) - For distributed testing, keep the secure defaults — leave
server.rmi.ssl.disable=false, generate the RMI keystore (create-rmi-keystore.sh), restrict the bind interface (java.rmi.server.hostname, firewallserver.rmi.port/server.rmi.localport), and do not setserver.rmi.ssl.disable=trueto "simplify setup" on an engine reachable from an untrusted network. (maintainer, 2026-06-03/04) - For distributed-mode isolation on JDK 24+ (Security Manager gone), use OS-level isolation, in order of preference: (1) container (
docker/podmanwith non-root user,--read-onlyroot FS,--tmpfs /tmp,--cap-drop=ALL, network scoped to the controller); (2) systemd hardening (NoNewPrivileges=true,CapabilityBoundingSet=,PrivateTmp=true,ProtectSystem=strict,ReadWritePaths=…); (3) dedicated locked-down OS user (least privilege). A referenceDockerfile/unit forjmeter-serveris a suggested PMC deliverable (tracked — §14 Q8). (maintainer, milamberspace 2026-06-04) - For HTTPS recording: remove the JMeter CA certificate from your OS/browser trust store after recording sessions; do not set
proxy.cert.validitylonger than the session needs. (maintainer, milamberspace 2026-06-04) - Only point JMeter at systems you are authorised to test, and treat responses from untrusted targets as potentially hostile to the parsers (hardening posture, not a guarantee). (maintainer)
- Vet third-party plugins before installing. (inferred)
- Don't open untrusted result/JTL files. (inferred)
- Running a
.jmxobtained from an untrusted source without isolation. (documented as the user's risk) - Disabling RMI SSL (
server.rmi.ssl.disable=true) to simplify distributed setup, then exposingjmeter-serveron an untrusted network — a widespread quick-start/tutorial antipattern that turns off the default mutual-TLS protection. (maintainer, milamberspace 2026-06-03) - Leaving the JMeter recording-proxy CA certificate permanently installed in the OS/browser trust store after a recording session, or setting
proxy.cert.validityto a long duration (e.g. years) — both widen the MITM exposure of a stolen CA key. (maintainer, milamberspace 2026-06-04) - Treating "open in GUI" as a safe way to inspect an untrusted plan (especially while the XStream allowlist is unenforced). (documented + maintainer)
- Load-testing or pentesting a third party's system without authorisation (a legal/ethical violation, not just a security risk; the negative counterpart of the §2 authorized dual-use). (maintainer, milamberspace 2026-06-04)
(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
.jmxtriggers code execution" — split into two cases: (a) execution via existing JMeter distribution classes during deserialization/UI initialisation isBY-DESIGN, consistent withsecurity.html; (b) execution via a class outside the JMeter distribution (XStream gadget chain, dynamically-compiled script triggered before Run) isVALID— the boundary the model intends to hold (currently under-enforced; §8/§9). (maintainer, vlsi + milamberspace 2026-06-04) - "Scripting/reflection/
Runtime.execpresent in the codebase" — needed to execute test plans;Runtime.exec()is used by the OS Process Sampler (by design — it runs commands the user configured) and byKeyToolUtilsto invokekeytoolfor proxy keystore management; reflection is required for plugin loading and test-element instantiation.BY-DESIGN/KNOWN-NON-FINDINGunless reachable from the distributed-RMI surface or the open-a-file-instantiates-an-out-of-distribution-class path. (maintainer, milamberspace 2026-06-04) - "JMeter listens on a local port (proxy)" — that is the user-initiated HTTPS recording proxy (
ProxyControl),BY-DESIGN; not an unintended listening service. (maintainer, milamberspace 2026-06-04) - "Keystore default password
changeitin properties" — scanners flag thechangeitvalue in commented-out lines ofuser.properties/jmeter.properties; thermi_keystore.jksis not shipped (operator-generated viacreate-rmi-keystore.sh/bat), so the comment is aKNOWN-NON-FINDING(operators should pick a strong password for their generated keystore). (maintainer, milamberspace 2026-06-04) - "RMI deserialization in distributed mode / jmeter-server is unauthenticated" — not
VALID: SSL + mutual client-auth are on by default and the engine won't start without a keystore. It only becomes reachable if the operator setserver.rmi.ssl.disable=true→OUT-OF-MODEL: non-default-config(closes CVE-2019-0187). (maintainer, 2026-06-03) - "Hostile SUT response (XXE/ReDoS/size bomb) crashes/exploits JMeter" — out of model; test only systems you own/are authorised to test (§3/§9). At most a
VALID-HARDENINGon the internal-audit track. (maintainer, vlsi + milamberspace 2026-06-04) - "XML external-entity (XXE) configuration in JMeter's XML processors (XPath Extractor, XStream)" — relevant only against a hostile SUT (out of model) or as part of the open-time XStream boundary (§8/§9). A targeted audit of whether
FEATURE_SECURE_PROCESSINGis enforced everywhere is aVALID-HARDENINGcandidate, not an in-model external-reporter finding. (maintainer, milamberspace 2026-06-04) - "JMeter makes outbound requests / can be pointed anywhere" — by-design; it is a load generator (§3).
- A change to the distributed-mode RMI/SSL defaults, or the JDK removing/altering an isolation primitive the model relies on. (maintainer/inferred)
- Merging an XStream class-loading allowlist (replacing
AnyTypePermission.ANYwith a classloader-based / manifest-declared / targeted-denylist scheme that still admits third-party-plugin classes) — would upgrade the §8.jmx-open guarantee from aspirational to enforced and tighten the §11a open-time triage split. (maintainer, vlsi + milamberspace 2026-06-04) - A new way to open (not run) a file that triggers instantiation/execution of a class outside the distribution. (maintainer)
- A decision to bring hostile-SUT response parsing into the model (currently out of model, §3/§9) — would add a new §8 claimed property. (maintainer)
- A change to the recording-proxy CA/cert-validity defaults. (maintainer)
- A report that cannot be routed to one §13 disposition → revise the model.
| 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 via an out-of-distribution class; misuse of a stolen recording-proxy CA key as a local boundary). | §8, §6, §7 |
VALID-HARDENING |
No §8 property broken, but a §11 misuse / hostile-SUT parser robustness is worth hardening on an internal-audit track (XXE/ReDoS/size-limits; louder open-time warnings; safer parser defaults). | §11, §9 |
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 (e.g. a hostile SUT). | §7 |
OUT-OF-MODEL: unsupported-component |
Lands in examples/ / demos / third-party plugins. |
§3 |
OUT-OF-MODEL: non-default-config |
Only manifests after the operator changed a runtime property away from its secure default — above all server.rmi.ssl.disable=true (turning off the default RMI mutual-TLS), or a very long proxy.cert.validity. No rebuild involved. |
§5a |
OUT-OF-MODEL: non-default-build |
Only manifests under a non-default build/compile-time setting (distinct from the runtime config opt-out above). | §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 |
Waves 1 and 2 were answered by the PMC (vlsi, milamberspace) on 2026-06-03/04 from a JMeter source review; the resolutions are folded into the sections above and the tags promoted to (maintainer). Retained here as a ratification record.
Wave 1 — security.html core + distributed defaults ✅ ANSWERED (2026-06-03/04)
- security.html core (trusted
.jmx; opening may execute; untrusted-plan isolation is the user's job) — confirmed canonical; ".jmx/scripting runs code" isBY-DESIGN. → §3/§9/§11a. - Distributed defaults — confirmed from
RmiUtils.java:server.rmi.ssl.disable=false, mutual client-auth (setNeedClientAuth(true)), keystore not shipped (engine won't start unprotected). The bind interface is not restricted by default (binds to the resolvedjava.rmi.server.hostname, can expose all interfaces on a multi-homed/public host). An unprotected engine requires the explicitserver.rmi.ssl.disable=trueopt-out →OUT-OF-MODEL: non-default-config. → §4/§5a/§8/§13. (maintainer, vlsi + milamberspace) examples// demos / third-party plugins out of scope — confirmed. → §2/§3. (maintainer, vlsi + milamberspace)
Wave 2 — in-model boundaries ✅ ANSWERED (2026-06-03/04)
4. Opening vs running — opening a .jmx is safe given trust in the distribution's existing classes (it deserializes + drives existing control/logic getters/setters); the in-model line is opening that instantiates/executes a class outside the distribution. The current setupXStreamSecurityPolicy() is effectively AnyTypePermission.ANY (a no-op), so this boundary is aspirational, not yet enforced — a scoped allowlist that still admits plugin classes is the tracked fix (Q8). → §4/§8/§9/§11a/§12. (maintainer, vlsi + milamberspace)
5. Hostile SUT — out of model, fully confirmed: the tester targets only systems they own/are authorised to test, so hostile-SUT parser robustness is VALID-HARDENING (internal audit), not a claimed property; no in-model carve-out. → §3/§7/§8/§9/§11a. (maintainer, vlsi + milamberspace 2026-06-04)
6. Security Manager — removed on JDK 24+ (JEP 486; deprecated JEP 411 from JDK 17), not the forward defense; security.html should be updated. The replacement on JDK 24+ is OS-level isolation (container / systemd hardening / dedicated OS user). Distributed protection is RMI-over-SSL + mutual client-auth. → §5/§9/§10. (maintainer, milamberspace 2026-06-04)
7. HTTPS recording proxy — modeled as a local trust boundary (CA private key on disk); default proxy.cert.validity=7 days is a sound default; risk is a stolen-and-still-trusted CA key. → §2/§4/§5a/§8/§10/§11/§11a. (maintainer, milamberspace 2026-06-04)
Wave 3 — tracked follow-ups (open; do not block the doc) 8. Tracked engineering/doc follow-ups (GitHub issues, not threat-model blockers, per the PMC):
- XStream allowlist — replace
AnyTypePermission.ANYwith a classloader-based / manifest-declared / targeted-denylist policy that still deserializes third-party-plugin classes (a staticorg.apache.jmeter.**list would break plugin test plans — vlsi). Closes the 12-year-oldCVE-2013-7285TODO. Upgrades the §8 open-time property from aspirational to enforced. (maintainer — direction agreed; exact mechanism open.) security.htmlbacklink — add the THREAT_MODEL.md link toxdocs/security.xml(the Velocity source forsecurity.html); without it the model is not discoverable from the canonical reporting page. (maintainer, milamberspace — track via PR/issue.)- Reference
Dockerfile/ systemd unit for hardenedjmeter-serveron JDK 24+ (the post-Security-Manager isolation deliverable). (maintainer, milamberspace.)
- Any further recurring scanner/fuzzer false positives to seed §11a beyond those now listed (scripting engines, reflection,
Runtime.exec, proxy port,changeit, XXE)? → §11a. (inferred — kept open for future scan output.) - Residual operator-trust / result-file assumptions — confirm the still-(inferred) items: that the operator fully controls the host /
user.properties/ plugins / (distributed) controller and engines, that those host-controlling parties are out of the adversary model, that result/JTL-file display does not instantiate arbitrary classes, and that re-opening an untrusted result/JTL file is the operator's responsibility. These are reasoned from architecture and not yet PMC-confirmed. → §2/§3/§5/§7/§8/§10.