Add draft threat model + SECURITY.md/AGENTS.md discoverability#6709
Add draft threat model + SECURITY.md/AGENTS.md discoverability#6709potiuk wants to merge 6 commits into
Conversation
Generated-by: Claude Code
|
Thanks for the fast turnaround. If you have a public skill to create the model, it would be great if you could share it (sure we can run, steer it and so on). I will check the output soon, however, my immediate thought is that we must forbid license headers in AGENTS.md. They are pure waste of tokens. AGENTS.md loads in every session, so the files must contain only the bare minimum. Sure license header is a pure waste when it comes to AGENTS.md and any other reference files the model consumes. PS. I consider using https://github.com/microsoft/apm for managing agent configurations and sharing skills, however, it is orthogonal to the PR. |
IN Airlfow we are using SPDX headers for all agentic skills for that very reason. If you want I can change ti this way in your PR as well, not sure if you are checking licences but this seemed to be result of the discussion we had on this subject in https://lists.apache.org/thread/j1tn63r2lf13v3d1tnnqff8fkcl4nx53 - while we do not have formal legal policy on that , seems that we can interpret the existing poliicy this way. |
|
I am absolutely happy to update the PR :) |
AGENTS.md is loaded by automated agents in every session, so the Apache license header is pure token overhead; drop it and exclude the file from RAT via .ratignore, per review feedback.
Strip the Apache license headers from the security docs as well, and revert the .ratignore AGENTS.md entry so RAT exclusions can be configured separately, per review feedback.
AGENTS.md, SECURITY.md and THREAT_MODEL.md no longer carry license headers, so list them in .ratignore to keep the RAT check green.
|
Done — stripped the Apache license headers from |
|
Ad the SKILL is linked above in the PR description |
| ## §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. |
| 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. |
There was a problem hiding this comment.
Opening a file involves test plan deserialization, thus it triggers class loading, and class initialization. The current design forces us to call getters/setters on the UI controls and the accompanying logic classes, so a mere "opening and browsing" the file would involve certain code execution.
I would say the line is "opening jmx is safe provided you trust all existing classes in jmeter distrubution". 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.
@milamberspace , WDYT?
There was a problem hiding this 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.
xstream.addPermission(NoTypePermission.NONE); // deny all...
xstream.addPermission(AnyTypePermission.ANY); // ...then allow ALLThe 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:
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)
.jmxfiles: the in-model guarantee is "opening is safe with respect to existing JMeter distribution classes". If a crafted.jmxtriggers instantiation of a class outside the JMeter distribution (via an XStream gadget chain), that is treated as aVALIDvulnerability. 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()appliesNoTypePermission.NONEthen immediately overrides it withAnyTypePermission.ANY, allowing instantiation of any JVM class during.jmxdeserialization. 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
.jmxtriggers code execution" — split into two cases:
- Execution via existing JMeter distribution classes during deserialization/UI initialisation:
BY-DESIGN, consistent withsecurity.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.
There was a problem hiding this comment.
The challenge is ensuring the allowlist
The issue is that allowlist should include third-party-plugin classes, otherwise the jmx won't deserialize.
So if we add a tightened allowlist, then the test plans with custom plugins won't load.
There was a problem hiding this comment.
@vlsi — you are absolutely right, and this is the constraint I hadn't fully thought through. A static org.apache.jmeter.** allowlist breaks every third-party plugin whose classes sit outside that namespace, which is a hard blocker.
A few directions for a proper fix (none blocking the threat model doc itself):
-
Dynamic allowlist from the plugin classloader — at startup, JMeter loads plugins from
lib/ext/. XStream could be configured to accept any class that was actually loaded by the plugin classloader, rather than a static package list. Standard-library gadget-chain classes (com.sun.**, etc.) don't pass through that classloader, so they'd still be blocked. This is the least invasive path for existing plugins. -
Manifest-based registration — each plugin jar declares its XStream-serialisable packages in
META-INF/jmeter-xstream-packages.txt; JMeter builds the allowlist at startup from those declarations. Requires a one-time migration for existing plugins, but explicit and auditable. -
Targeted denylist — instead of allowlisting, block specific packages known to supply gadget chains (the CVE-2013-7285 class). Less strict than an allowlist but non-breaking.
For the threat model doc: I'd suggest adding a note in §9 or §12 that setupXStreamSecurityPolicy() does not currently enforce a class-loading boundary (the effective policy is AnyTypePermission.ANY — a no-op), and tracking the classloader-based approach as a §12 condition that would strengthen the §8 "opening is safe given trust in existing classes" property. The aspirational guarantee is already correctly scoped in §8; we just need to be honest that the implementation hasn't caught up yet.
milamberspace
left a comment
There was a problem hiding this comment.
PMC review of the draft threat model (v0) — 6 inline comments below addressing the open questions in §14, one identified gap (HTTPS recording proxy), and a correction on the Security Manager forward story for JDK 24+.
| - **`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.) |
There was a problem hiding this comment.
Wave 1 / Q2 — RMI SSL default posture: answer from source code
After reviewing src/core/src/main/java/org/apache/jmeter/rmi/RmiUtils.java:
server.rmi.ssl.disabledefaults tofalsein code → SSL is required by defaultserver.rmi.ssl.keystore.filedefaults tormi_keystore.jks, a file that is not shipped with the JMeter distribution (it must be generated by runningcreate-rmi-keystore.sh/create-rmi-keystore.bat)- Without the keystore file present on disk, the SSL connection fails for both a legitimate controller and an attacker
- An unprotected (no-SSL) deployment requires an explicit opt-out:
server.rmi.ssl.disable=true
Proposed triage: OUT-OF-MODEL: non-default-build — an attacker cannot reach an unprotected engine without the operator actively disabling SSL.
However, disabling SSL to simplify setup is a widespread real-world antipattern found in many tutorials and quick-start guides. Suggest adding to §11 (Known misuse patterns):
"Disabling RMI SSL (
server.rmi.ssl.disable=true) to simplify distributed setup, then exposingjmeter-serveron an untrusted network."
| **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. | ||
| 5. **Hostile SUT:** is a malicious *system under test* (hostile HTTP/JDBC responses hitting JMeter's XPath/JSON/regex extractors — XXE, ReDoS, size bombs) **in scope**, or is the SUT assumed trusted/owned by the tester? Proposed: SUT semi-trusted; parser robustness is best-effort, not a claimed property. → §6/§7/§8. | ||
| 6. The platform **Security Manager is deprecated/removed in modern JDKs**, yet it is the documented isolation recommendation. What is the forward isolation story for distributed mode? → §5/§9. |
There was a problem hiding this comment.
Wave 2 / Q6 — Security Manager: precise deprecation timeline + recommended forward path
The phrasing "deprecated/removed in modern JDKs" should be more precise:
| JDK | Status |
|---|---|
| 17 | Security Manager deprecated for removal (JEP 411) |
| 18–23 | Deprecated, still functional (prints a warning on startup) |
| 24 | Security Manager fully removed (JEP 486) — no longer available at all |
Since JMeter 6.0 sets JDK 17 as the minimum and users may run on JDK 24+, the documented isolation recommendation is not actionable on JDK 24+.
Recommended forward path for the PMC (JDK 24+):
The Security Manager enforced a policy at the JVM level: it restricted which classes could perform privileged operations (file I/O, network, reflection, exec, etc.). The equivalent isolation must now come from outside the JVM. In order of preference:
1. Container isolation (preferred)
Run jmeter-server in a Docker or Podman container:
docker run --rm --user 1000:1000 --read-only --tmpfs /tmp --cap-drop=ALL --network=<controller-network> -v /path/to/results:/results jmeter-server-image
Key settings: non-root user, read-only root filesystem, no Linux capabilities, network scoped to the controller. A reference Dockerfile for jmeter-server would be a concrete and low-effort PMC deliverable.
2. systemd service hardening (bare-metal alternative)
A systemd unit for jmeter-server with:
[Service]
NoNewPrivileges=true
CapabilityBoundingSet=
PrivateTmp=true
ProtectSystem=strict
ReadWritePaths=/path/to/results3. Dedicated OS user (minimum baseline)
Run jmeter-server as a locked-down system account with minimal filesystem permissions (principle of least privilege).
Suggested model updates:
- §5: clarify that Security Manager is removed (not just deprecated) on JDK 24+
- §9: add — "On JDK 24+, the Security Manager is unavailable; OS-level isolation (container, systemd hardening, or dedicated OS user) is the recommended replacement"
- Open a GitHub Issue to track the documentation of this migration path and a potential reference
Dockerfile
| | 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)* | |
There was a problem hiding this comment.
Missing component: HTTPS recording proxy (ProxyControl)
The component-family table does not include the HTTPS recording proxy, which is a significant JMeter feature with its own trust boundary and security surface.
When used in recording mode (HTTPS), JMeter:
- Generates a local Root CA certificate (
ApacheJMeterTemporaryRootCA.*) stored in a keystore on the user's machine - Dynamically issues per-host TLS certificates signed by that CA (on the fly, per target hostname)
- Requires the user to install the JMeter CA into their OS or browser trust store
The security risk: if the JMeter CA private key (stored on disk in the keystore) is compromised while the CA certificate is still trusted by the browser/OS, an attacker can issue fraudulent certificates for any domain — accepted silently by the browser, enabling MITM attacks.
Good news on defaults: proxy.cert.validity defaults to 7 days (ProxyControl.java, line 202: JMeterUtils.getPropDefault("proxy.cert.validity", 7)). This limits the exposure window and is a sound security default. The risk scenario of a very long-lived CA (e.g. 10 years via proxy.cert.validity=3650) is an opt-in misconfiguration, not the default — the model should note this positive default explicitly.
Suggested additions to the model:
- §2 component table: add a row —
| HTTPS recording proxy | ProxyControl (GUI or CLI) | local filesystem (CA keystore) + MITM on local HTTPS traffic | **In — local trust boundary (CA private key)** *(inferred)* | - §4: note the JMeter CA private key as a local trust boundary (analogous to running a private CA on the workstation)
- §10 (downstream responsibilities): "Remove the JMeter CA certificate from your OS/browser trust store after recording sessions; do not set
proxy.cert.validityto a duration longer than your recording session needs" - §11 (known misuse patterns): "Leaving the JMeter CA certificate permanently installed in the OS/browser trust store after a recording session; setting
proxy.cert.validityto a long duration (e.g. years)"
| - "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). |
There was a problem hiding this comment.
§11a — Additional non-findings to seed
Some recurring scanner/fuzzer false positives not yet listed:
-
Runtime.exec()calls in the codebase — used by the OS Process Sampler (by design: it executes system commands the user configured) and byKeyToolUtilsto invokekeytoolfor proxy keystore management.BY-DESIGN/KNOWN-NON-FINDING. -
Java reflection — required for plugin loading and test element instantiation via the plugin architecture.
KNOWN-NON-FINDING. -
JMeter listening on a local port as an HTTP/HTTPS proxy — this is the HTTPS recording proxy (
ProxyControl); it is user-initiated andBY-DESIGN. Not an unintended listening service. -
Keystore file with a default password (
changeit) — scanners may flag thechangeitvalue in commented-out lines ofuser.properties/jmeter.properties. Thermi_keystore.jksfile is not shipped with the distribution; it is generated by the operator viacreate-rmi-keystore.sh/bat.KNOWN-NON-FINDINGfor the property comment; operators should of course choose a strong password for their generated keystore. -
XML parsing — external entity configuration — worth a targeted audit of JMeter's XML processors (XPath Extractor, XStream
.jmxdeserialization). IfFEATURE_SECURE_PROCESSINGis already enforced everywhere, add to §11a. If not, this may be aVALID-HARDENINGcandidate (XXE protection against hostile SUT responses).
| - **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 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. |
There was a problem hiding this comment.
§1 Coexistence — backlink from security.html not included in this PR
This line states that security.html "should link here for the expanded model" — but xdocs/security.xml (the Velocity/Maven source that generates security.html) is not modified in this PR.
Without the backlink, the threat model exists in the repository but is not discoverable from the canonical reporting page, reducing its effectiveness as a triage reference for security reporters and automated scanners.
Suggested resolution:
Add to the "Security Model" section of xdocs/security.xml:
<p>
For the full threat model, adversary model, and triage dispositions,
see <a href="https://github.com/apache/jmeter/blob/master/THREAT_MODEL.md">THREAT_MODEL.md</a>.
</p>Either include this in the current PR or open a GitHub Issue as a tracked follow-up. Please do not leave it as an informal note — the link is what makes the model actionable for reporters.
| 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)* |
There was a problem hiding this comment.
§5a — jmeter-server bind interface: answer to the (inferred) item
jmeter-server does not bind to a restricted interface by default. The RMI registry and server socket bind to the address that java.rmi.server.hostname resolves to — typically the machine's primary hostname or IP. On a multi-homed host or a machine with a public IP, this can expose the RMI port on all interfaces.
Relevant properties for operators (all configurable in jmeter.properties or user.properties):
| Property | Default | Purpose |
|---|---|---|
java.rmi.server.hostname |
(machine hostname) | Restricts which IP the RMI server advertises and binds to; set to 127.0.0.1 for loopback-only |
server.rmi.port |
1099 |
RMI registry port |
server.rmi.localport |
(dynamic) | Server socket port for the remote engine object; fix this value if you need precise firewall rules |
Suggested model clarification in §5a: note that jmeter-server does not bind to a restricted interface by default, and that operators should use java.rmi.server.hostname and/or perimeter firewall rules to limit exposure — especially on multi-homed or internet-facing machines. This is particularly important when SSL is disabled (see the server.rmi.ssl.disable discussion).
|
On ASF license headers in AI agent-facing files Following up on @vlsi's comment about token waste in Why license headers should be omitted from AI-facing files: Files such as
Recommendation for future files of this type: any file whose primary consumer is an AI agent (not a human reader or a build tool) should be added to The current PR's approach — removing the headers and updating Broader suggestion: an ASF-level discussion on AI-facing files This raises a question that goes beyond JMeter alone. As AI tooling becomes standard in open source development, it would be worth opening a discussion within the ASF (e.g. via the The current full license header is clearly overkill for these files. A reasonable middle ground could be a lightweight attribution line — something like: This would:
A shared ASF convention on this point would benefit all projects adopting |
@milamberspace - of course - I 100% agree with it. Chiming in in https://lists.apache.org/thread/j1tn63r2lf13v3d1tnnqff8fkcl4nx53 and stating your position in the thread might be a good first start - as well as anyone else who thinks like it. This is in the camp of legal now to clarify it - and we need people like you to take the lead and drive it to policy change. I am 100% happy to support you! |
|
Generally - the more people we have stating their poistion in those discussions - the better! Please do so. |
… Manager, open-vs-run, hostile SUT) Folds in the Wave-1/2 answers from @vlsi and @milamberspace (2026-06-03): - RMI: SSL on by default + mutual client-auth + keystore-not-shipped, so an unprotected jmeter-server requires an explicit server.rmi.ssl.disable=true opt-out -> OUT-OF-MODEL: non-default-config (not VALID, not 'build'). - Security Manager: deprecated (JEP 411), no longer the forward defense; the real distributed defense is RMI-over-SSL. - Opening vs running: opening a .jmx is safe given trust in existing distribution classes; only generating+executing a NEW class on open is in model. - Hostile SUT: out of model (test only systems you own); parser robustness is hardening, not a claimed property (pending milamberspace's final word). - Adds the 'disable RMI SSL then expose jmeter-server' misuse; §14 waves 1-2 marked answered. Generated-by: Claude Code
Generated-by: Claude Code
|
Pushed a v1 folding in your review — thanks @vlsi @milamberspace. What changed:
On the broader "AI-facing files" point (@milamberspace): strongly agree it's worth an ASF-level convention. Happy to help take it to the relevant list. |
|
Q5 (hostile SUT) — confirmed out of model Agreed — no in-model carve-out needed. The trust boundary is clear: an operator tests only systems they own or are authorised to test. Parser robustness against a hostile SUT (XXE on XPath Extractor, ReDoS on regex patterns, unbounded response sizes) is desirable hardening, but classifying it as a claimed security property would essentially mean saying "JMeter is safe to point at attacker-controlled infrastructure" — which is not the intended use case and would be an untenable claim. Classification: VALID-HARDENING (internal audit track, not an in-model threat). §9 "safe response handling — UNSPECIFIED / best-effort" is the right framing. The current v1 wording works well. §14 wave 2 can be fully marked answered. |
milamberspace
left a comment
There was a problem hiding this comment.
One additional suggestion on §2 scope — see inline comment below.
|
|
||
| ## §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)* |
There was a problem hiding this comment.
§2 — Suggested addition: authorized penetration testing as a recognized use case
JMeter is widely used — and distributed in penetration testing toolkits — as a tool for authorized security assessments, in addition to its primary load/performance testing purpose. Its scripting capabilities (JSR223/Groovy/BeanShell), parameterized datasets (CSV Dataset Config), and broad protocol support (HTTP, JDBC, LDAP, JMS, …) make it naturally suited for this work.
This does not change the trust model: whether the operator is a performance engineer or an authorized pentester, they are the trusted party running a .jmx they control against a target they are authorized to test.
Suggested addition to §2 (after the "Primary use" bullet):
Secondary / dual-use: JMeter is used by security professionals as a tool for authorized penetration testing and security assessments — rate-limit testing, parameterized enumeration, fuzzing, and custom scenarios via scripting. This is a recognized legitimate use; the operator-trust model is unchanged. Conducting such tests against systems without authorization is a legal and ethical violation, already covered by §11.
Why it matters for triage: without this acknowledgment, a report such as "JMeter can be used to enumerate endpoints / perform credential stuffing / stress-test authentication" might be filed as a vulnerability. With this addition, the triage answer is immediate: BY-DESIGN / OUT-OF-MODEL: trusted-input for authorized pentesting; §11 misuse for unauthorized use.
Note: §11 already carries "Load-testing a third party's system without authorisation (also a legal issue)" (line 123). The suggested §2 addition is the positive counterpart — acknowledging the legitimate use case that makes §11's boundary meaningful.
| # Agent Guide for jmeter | ||
|
|
||
| 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. |
There was a problem hiding this comment.
| # Agent Guide for jmeter | |
| 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. | |
| Security model: [SECURITY.md](./SECURITY.md) |
Frankly, we do not have an overwhelming amount of AI-reported issues (lucky we), so I would prefer to keep a bare minimum in agents.md
There was a problem hiding this comment.
Agree with @vlsi. The surrounding prose explains what AGENTS.md is — useful for a human browsing the repo, redundant for the agent loading it. A single pointer is all that's needed.
If you want to keep the heading # Agent Guide for jmeter for repo discoverability (GitHub's file listing renders it), that's fine but not required. The suggestion works as-is.
What this is
A draft threat model for Apache JMeter, proposed by the ASF Security team for the JMeter PMC to review, correct, or reject — drafted by the Security team's threat-model tooling from JMeter's public docs and
security.html, following the ASF Security threat-model rubric.It is built on the existing
security.html: that page's "Security Model" statements are lifted in verbatim as the documented core, and this document adds the surrounding threat-model structure (adversary model, in/out scope, properties, known non-findings, triage dispositions). It is a strict superset — nothing insecurity.htmlis weakened; that page stays the canonical reporting/policy page and should link here for the expanded model.This PR:
THREAT_MODEL.md— the draft model;SECURITY.md— a short security policy linking the threat model (andsecurity.html);AGENTS.mdwith a## Securitysection, so the chainAGENTS.md → SECURITY.md → THREAT_MODEL.mdis mechanically discoverable by automated security scanners.How to read it
Every claim is provenance-tagged: (documented) (from JMeter's docs/
security.html/repo), (inferred) (reasoned from architecture, not yet confirmed), (maintainer) (confirmed by the PMC). This v0 is ~10 documented / ~26 inferred. The §14 Open questions section collects the inferred claims into waves for the PMC to confirm or correct. The model leads with the documentedBY-DESIGNcore — JMeter executes the (trusted) test plan it is given, and isolating untrusted.jmxis the user's responsibility — and then focuses the in-model boundaries on:jmeter-server) and its RMI-over-SSL + Security-Manager defaults (wave 1);.jmxfiles (wave 2);Nothing here is a requirement — the model is for the PMC to own. Comment inline, edit the branch, or reply on the email thread.