Security & Responsible Load Testing
|
This content was generated with the assistance of AI and should be verified against the official documentation before being relied on in production. |
The reference material consulted while preparing these pages is listed in the section bibliography.
A load generator is a tool for sending a very large amount of traffic on purpose. Used against a system nobody agreed
to test, it is indistinguishable from a denial-of-service attack; used carelessly against your own system, it can
leak the credentials and personal data that flow through it. JMeter itself is also software with attack surface: it
executes whatever a .jmx file tells it to, it can install a root certificate authority in your browser, and in a
distributed run it accepts remote commands over the network. This page collects what a team has to settle before,
during and after a load test so that the test is authorised, the data stays protected and JMeter does not become the
weakest machine on the network.
It was written against Apache JMeter 5.6.3, the latest release at the time of writing, on Java 21 (5.6.x needs Java 8
or newer; this guide recommends 17 or newer, 21 preferred). The examples were run on a 5.6.3 installation with Java 21.
The Plugins Manager referred to is 2.0. JMeter 6.0 is not released; where the development branch plans a change that
matters here (Java 17 as the minimum, updated bundled libraries), the text says "planned per changes.xml on master".
The JMeter facts come from the official security page, best practices, remote testing chapter, component reference and
properties reference. Authorisation and coordination are not covered by the JMeter manual; that part is general
practice for responsible testing, and the only external rule quoted is a cloud provider’s published testing policy.
Everything on this page is defensive. It describes how to test systems you own or are authorised to test, and how to protect the test and its data; it does not describe how to evade detection or overload systems you are not responsible for.
Where the risks are
The picture below follows the Bookshelf test from the plan file to the report and marks where something sensitive is stored or exposed. Each box is a section of this page.
| Asset | Risk | Section |
|---|---|---|
Permission to send load |
Unauthorised traffic looks like an attack; shared infrastructure suffers |
|
|
Passwords stored in clear; untrusted plans can run arbitrary code |
|
Results and responses |
Tokens, personal data and request bodies written to disk and CI artefacts |
|
Recorder root CA |
Anyone with the keystore can impersonate any site to the browser that trusts it |
|
Distributed nodes |
Remote execution agents on the network |
|
BeanShell server |
Unauthenticated remote shell into JMeter and the host |
|
JMeter, Java and plugins |
Known vulnerabilities in old versions and in third-party jars |
Keeping JMeter, Java and plugins updated, Judging third-party plugins |
Authorisation and rules of engagement
Only load-test systems you own or are explicitly authorised to test. A load test that saturates a server is, from the receiving side, a denial-of-service event: the same symptoms, the same alarms, and potentially the same consequences for other customers of shared infrastructure. Owning the application is not enough when it runs on someone else’s infrastructure: the hosting provider, the CDN, the API gateway, the database service and every third-party API that the journey touches are also on the receiving end.
Before the first non-smoke run, get written agreement on the points below. A short document or ticket is enough; what matters is that the people who could be paged by the test know it is coming.
| Item | What to agree |
|---|---|
Owner and approver |
Who owns the system under test and who approved this test, by name. |
Target |
Exact host names, IP ranges and environments. For Bookshelf: |
Source |
Which load generators send the traffic and from which addresses, so operations and security teams can recognise it. |
Window |
Start, end and time zone. Avoid windows that overlap backups, batch jobs or other teams' tests. |
Peak load |
The highest arrival rate or number of threads, in numbers. For the Bookshelf load profile: 50 threads with a 3 s think time and about 0.2 s response time, so about 50 / 3.2 ≈ 15.6 requests per second at full load; a stress profile states its ceiling the same way. |
Stop conditions |
Error rate, latency or resource thresholds at which the test is stopped, and who may stop it. |
Kill switch |
How to stop it: |
Contacts |
On-call engineers for the system, the load-test operator, and the people at each provider who must be told. |
Data |
Which accounts and data the test uses (test accounts only), and what happens to the results afterwards. |
Coordinate with providers. Tell everyone whose infrastructure carries the traffic:
-
Your own operations and security teams. Intrusion detection, web application firewalls and rate limiters react to load tests. Agree whether the generators are allow-listed for the test or whether the test should go through the same protection as real users (often the more honest measurement).
-
Cloud and hosting providers. Each publishes its own rules for load and stress tests. For example, the Amazon EC2 Testing Policy treats high-volume tests of legitimate traffic towards a target that can handle it as stress tests, explicitly prohibits volumetric network DDoS simulations from the EC2 platform, and refers DDoS simulations to a separate policy. Read the current policy of every provider involved, on both the generator side and the target side, before the test.
-
CDNs, API gateways and SaaS front ends. Their protection may block the generators or, worse, let the test through and bill it.
-
Third-party APIs called by the system under test. A payment, email, SMS or identity provider should not receive load-test traffic. Point the system under test at a sandbox or a stub for the test, and check with the provider before sending any volume even to a sandbox.
Make the traffic recognisable. Add an identifying header with an HTTP Header Manager at the Test Plan level (Add → Config Element → HTTP Header Manager), so that logs and dashboards on the server side can separate test traffic from real traffic, and give the generators stable, documented addresses. A header is a label, not a security control: anyone can send it, so never let the system under test relax authentication or rate limits because of it.
<HeaderManager guiclass="HeaderPanel" testclass="HeaderManager" testname="Identify load-test traffic">
<collectionProp name="HeaderManager.headers">
<elementProp name="" elementType="Header">
<stringProp name="Header.name">X-Load-Test</stringProp>
<stringProp name="Header.value">bookshelf-load ${__P(run_id,local)}</stringProp>
</elementProp>
</collectionProp>
</HeaderManager>
<hashTree/>
Run with -Jrun_id=2026-10-14-staging to stamp every request with the run that sent it. The header name is a
convention of this guide, not something JMeter or the server requires.
Start small. Run the smoke profile (1 thread) first, then a fraction of the agreed peak, and watch the system and the error rate before going higher. A plan that is wrong (a missing think time, an unbounded loop, a token extractor that fails so every request is retried) produces far more traffic than intended, and the first minute of a small run reveals it. The page on running tests in CLI mode shows how to read the live summariser for this.
Keeping secrets out of .jmx files
A .jmx file is an XML document that travels: it is committed to Git, attached to tickets, copied to every load
generator and uploaded to CI. Anything typed into it is in all of those places. The component reference marks every
password field that is saved as typed with the same sentence, "stored unencrypted in the test plan". In 5.6.3 that
applies to:
| Element | Field stored unencrypted |
|---|---|
HTTP Request, HTTP Request Defaults |
Proxy server password |
HTTP Authorization Manager |
Password of each row (Basic, Digest, Kerberos) |
JDBC Connection Configuration |
Password |
JMS Publisher, JMS Subscriber |
Password |
SMTP Sampler, Mail Reader Sampler |
Login password |
LDAP Request, LDAP Extended Request |
Password (bind and login) |
TCP Sampler |
Password (not used by the default implementation) |
Login Config Element |
Default password |
The same applies to anything else stored as plain text: an API key in a Header Manager, a client secret in a request
body, a token pasted into a User Defined Variable. Recorded plans add one more case: the recorder always strips the
Cookie and Authorization headers (proxy.headers.remove), but it keeps request bodies, so recording a login
with a real password writes that password into the login sampler. Record with test accounts only, and replace the
recorded values with variables as described on the recording page.
Source: HTTP Authorization Manager (Component Reference) and Test Script Recorder configuration (Properties Reference)
Where secrets should come from
The plan holds only references, such as ${adminPassword}; the values arrive at run time. The options, from the
most to the least suitable for a shared or CI environment:
| Source | How the plan reads it | Exposure |
|---|---|---|
A properties file passed with |
|
The file on the generator. |
An environment variable set by the CI system’s secret store |
|
The process environment. CI systems mask registered secrets in their logs. |
A CSV file of test accounts outside version control |
CSV Data Set Config variables such as |
The file on every generator; acceptable for placeholder or test-only accounts. |
|
|
Visible to other users in the process list and saved in shell history. Avoid for real secrets. |
The Bookshelf plan defines its secrets once, in a User Defined Variables element at the top of the Test Plan, so that every sampler refers to variables and the sources are visible in one place:
-
Select the Test Plan and choose Add → Config Element → User Defined Variables. Name it Secrets (from environment and properties).
-
Add a row
apiKeywith the value${__groovy(System.getenv('BOOKSHELF_API_KEY') ?: '')}. -
Add a row
adminPasswordwith the value${__P(admin_password,)}. -
Use
${apiKey}and${adminPassword}in Header Managers, Authorization Managers and request bodies.
<Arguments guiclass="ArgumentsPanel" testclass="Arguments" testname="Secrets (from environment and properties)">
<collectionProp name="Arguments.arguments">
<elementProp name="apiKey" elementType="Argument">
<stringProp name="Argument.name">apiKey</stringProp>
<stringProp name="Argument.value">${__groovy(System.getenv('BOOKSHELF_API_KEY') ?: '')}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
<elementProp name="adminPassword" elementType="Argument">
<stringProp name="Argument.name">adminPassword</stringProp>
<stringProp name="Argument.value">${__P(admin_password,)}</stringProp>
<stringProp name="Argument.metadata">=</stringProp>
</elementProp>
</collectionProp>
</Arguments>
<hashTree/>
The secrets file holds a placeholder here; in a real setup it is created by the deployment of the load generator and never committed:
# secrets.properties - chmod 600, not in version control
admin_password=placeholder-admin-password
The run below uses secrets-demo.jmx: the element above plus one Debug Sampler, which makes the values visible for
the demonstration in the next section. A real run uses bookshelf-load.jmx the same way.
chmod 600 secrets.properties
BOOKSHELF_API_KEY=placeholder-api-key \
jmeter -n -t secrets-demo.jmx -q secrets.properties -l a.jtl
Creating summariser <summary>
Created the tree successfully using secrets-demo.jmx
Starting standalone test @ 2026 Oct 14 13:32:08 CEST (1791977528509)
Waiting for possible Shutdown/StopTestNow/HeapDump/ThreadDump message on port 4445
summary = 1 in 00:00:00 = 22.2/s Avg: 3 Min: 3 Max: 3 Err: 0 (0.00%)
Tidying up ... @ 2026 Oct 14 13:32:09 CEST (1791977529365)
... end of run
In CI, the same command reads BOOKSHELF_API_KEY from the pipeline’s secret store and writes secrets.properties
from another secret at the start of the job. The page on CI/CD with Maven, Docker and GitHub Actions later in this
section shows the pipeline side.
Source: Functions (User Manual), Parameterising tests (Best Practices) and Command-line options (User Manual)
__env is a plugin function. The __env function seen in many examples comes from the jpgc-functions
plugin, not from core JMeter; the __groovy form above needs nothing beyond the bundled Groovy. For the per-element
details of the Authorization Manager and Header Manager, see
HTTP Sessions, Headers, Cookies & Authentication;
for -q, -J and __P, see Properties, Variables & Functions.
Secrets in -D system properties. Keystores for client certificates are passed as system properties
(javax.net.ssl.keyStorePassword). Expand them from an environment variable as in
HTTP Requests, and remember that the expanded value is still visible in the
process list while JMeter runs; -S with a system-properties file readable only by the user avoids that.
Distributed runs. Properties set on the controller with -J or -q are local to it; the remote servers evaluate
__P against their own properties. -G sends properties to every server over RMI. Put the secrets file on every
node, or send secrets with -G only when RMI runs over SSL (see below).
Checking a plan before committing it
A quick search catches the common mistakes. Every element with a password field writes a password property, so a
non-empty value that is not a variable reference is suspect:
grep -nE '<stringProp name="[^"]*[Pp]assword[^"]*">[^$<][^<]*</stringProp>' *.jmx
grep -nE 'Bearer [A-Za-z0-9._-]{20,}|api[_-]?key' *.jmx
Both commands print nothing for a clean plan. A secret-scanning tool in the repository (for example in a pre-commit hook) gives broader coverage; the JMeter project does not ship one.
Personal data in results and responses
Load tests produce files: the JTL results file, jmeter.log, the HTML dashboard, optional XML files with response
bodies, and anything a JSR223 element writes. Which of these contain personal or confidential data depends on what was
saved.
| Output | Default content | What can leak |
|---|---|---|
CSV JTL ( |
Times, labels, codes, messages, thread names; no bodies, headers or URLs |
Sampler labels built from data ( |
XML JTL, or a listener configured to save more |
Same fields, plus whatever is switched on |
Response bodies ( |
View Results Tree, Debug Sampler |
Everything, including all variables |
A Debug Sampler prints every JMeter variable, secrets read from the environment included, into its response. |
Test Plan Functional Test Mode |
Off |
When on, every listener with a file saves the response data of every sample. |
HTML dashboard |
Aggregates, labels, error messages |
Labels and error messages, as above. |
|
Start-up, warnings, errors |
Stack traces and anything a script logs with |
The defaults of the save properties are all false for bodies, headers, sampler data and URLs, which is the right
starting point. The demonstration below checks the CSV file of the run above, then repeats the run with XML output and
response data switched on.
grep -c placeholder a.jtl
BOOKSHELF_API_KEY=placeholder-api-key \
jmeter -n -t secrets-demo.jmx -q secrets.properties -l b.jtl \
-Jjmeter.save.saveservice.output_format=xml \
-Jjmeter.save.saveservice.response_data=true
grep -n placeholder b.jtl
0
13:adminPassword=placeholder-admin-password
14:apiKey=placeholder-api-key
The CSV file contains neither value; the XML file with response data contains both, because the Debug Sampler put them in its response. The rules that follow from this:
-
Save responses only on error. Keep the main
-lfile in CSV without bodies, and capture failed responses with a separate errors-only listener, as described in Listeners & Results Files. Leave Save Request Headers and Save Sampler Data off: they contain theAuthorization: Bearerheader and the login body. -
Remove debugging elements before a load run. Disable or delete Debug Samplers, Debug PostProcessors and View Results Tree listeners; the manual says View Results Tree must not be used during load tests anyway.
-
Keep Functional Test Mode off in load-test plans.
-
Do not put secrets or personal fields in
sample_variables. Every listed variable becomes a column of every results row. -
Use synthetic data.
users.csvholds test accounts created for the test, and search terms are made up. If a test needs production-like data, use a masked or generated copy, never a raw production extract, and let the data owner decide whether it may leave the production environment. -
Treat results as data with an owner. Store JTL files, dashboards and logs where the access rules match their content, set a retention period for CI artefacts, and delete error bodies once the investigation is over. Personal data in a results file falls under the same data-protection rules as personal data anywhere else.
The recorder root CA
To record HTTPS, the HTTP(S) Test Script Recorder acts as a deliberate man in the middle: it generates a root CA,
exports it as ApacheJMeterTemporaryRootCA.crt, and signs a certificate for every host the browser visits. Once a
browser trusts that root CA, it trusts every certificate signed by it, with no warning, until the certificate expires
or is removed. The component reference states the consequence plainly: anyone who gets hold of the keystore and its
password can create certificates that browsers trusting the JMeter root CA will accept. For that reason JMeter
generates random keystore and key passwords (kept in the local preferences area) and uses a short validity, 7 days by
default (proxy.cert.validity), and the manual asks that only trusted users have access to the host with the
keystore. The certificate’s own subject repeats the warning: _ JMeter Root CA for recording (INSTALL ONLY IF IT S YOURS).
How to keep the exposure small:
-
Trust the CA in a throw-away browser profile, not in the operating system store and not in your everyday browser profile. Delete the profile, or remove the certificate, when recording is over.
-
Never install it on a shared machine, and never install a JMeter CA that someone else generated.
-
Keep the default 7-day validity. A longer
proxy.cert.validitytrades convenience for a longer window of exposure if the keystore leaks. -
Protect
proxyserver.jks. It lives in the JMeterbindirectory by default (proxy.cert.directory). Do not commit it, copy it between machines or bake it into images; delete it to force a fresh CA, as shown on the recording page. -
Stop the recorder when you are done. It listens on port 8888 by default; while it runs, anything that can reach that port can send traffic through it. Keep the port closed to other machines with the host firewall.
-
Record only test accounts, as explained above: recorded bodies end up in the plan.
The step-by-step installation, regeneration and the certificate properties are on Recording & cURL Import. Tools → Import from cURL needs no certificate at all and is the safer way to capture a few API calls.
RMI over SSL for distributed runs
In a distributed test, the controller sends the whole test plan to each remote server over Java RMI, and each server
executes it. The remote testing chapter puts the risk directly: JMeter is basically a remote execution agent on both
the server and the client side, which a malicious party could use to gain further access once it has compromised one
of them. Since JMeter 4.0, RMI uses SSL by default; the keystore must exist on every node, or SSL must be switched off
with server.rmi.ssl.disable=true.
Never disable SSL on a network you do not fully control. Turning it off makes the remote servers accept test plans, and therefore code, from anyone who can reach their RMI ports. The books (Pro Apache JMeter ch. 6, JMeter Cookbook ch. 5, JMeter 2.11 to 3.0) describe distributed testing before SSL existed; follow the current manual instead. The page on distributed testing later in this section covers the topology, ports and sample senders; this section covers only the security side.
The RMI SSL properties
| Property | Default | Meaning |
|---|---|---|
|
|
Keystore type; JKS and PKCS12 are commonly supported. |
|
|
Keystore with the private key. |
|
|
Keystore password. |
|
|
Alias of the key. |
|
value of the keystore type |
Truststore type. |
|
value of the keystore file |
File with the trusted certificate. |
|
value of the keystore password |
Truststore password. |
|
|
|
Creating and distributing the keystore
The manual’s simplest setup is one key pair shared by all servers and the controller, created with
bin/create-rmi-keystore.sh (or .bat) and copied to every node. In 5.6.3 that script runs keytool with a fixed
store password changeit, the alias rmi, a 2048-bit RSA key and a validity of 7 days, so the keystore has to be
recreated before each test campaign. The fixed password is the documented default, which is acceptable only because
the file itself must stay private; anyone with the file can join the cluster.
A keystore with its own password works the same way when the properties point at it. The following was run with the
JDK 21 keytool; the password is a placeholder:
keytool -genkeypair -keyalg RSA -keysize 3072 -alias rmi -validity 30 \
-storetype PKCS12 -keystore rmi_keystore.p12 \
-storepass 'placeholder-change-me' -dname "CN=rmi, OU=Load testing, O=Bookshelf"
Generating 3072-bit RSA key pair and self-signed certificate (SHA384withRSA) with a validity of 30 days
for: CN=rmi, OU=Load testing, O=Bookshelf
# rmi-ssl.properties - same file on the controller and every server, chmod 600
server.rmi.ssl.keystore.type=PKCS12
server.rmi.ssl.keystore.file=/opt/jmeter/secrets/rmi_keystore.p12
server.rmi.ssl.keystore.password=placeholder-change-me
server.rmi.ssl.keystore.alias=rmi
Start each server with the file (jmeter-server passes extra arguments to JMeter):
jmeter-server -Djava.rmi.server.hostname=10.0.0.21 -q rmi-ssl.properties
On a 5.6.3 server the first line of output names the SSL socket factories and the keystore in use (shown here with the address and path of the example, and abbreviated):
Created remote object: UnicastServerRef2 [liveRef: [endpoint:[10.0.0.21:61528,SSLRMIServerSocketFactory(host=/10.0.0.21, keyStoreLocation=/opt/jmeter/secrets/rmi_keystore.p12, type=PKCS12, trustStoreLocation=/opt/jmeter/secrets/rmi_keystore.p12, type=PKCS12, alias=rmi),SSLRMIClientSocketFactory(...)](local),objID:[...]]]
A server started without a keystore refuses to start rather than falling back to plain RMI:
Server failed to start: java.rmi.server.ExportException: Listen failed on port: 0; nested exception is:
java.io.FileNotFoundException: rmi_keystore.jks (No such file or directory)
That message means "create or copy the keystore", not "disable SSL". A controller and a server holding different
keystores fail the TLS handshake with PKIX path building failed, which is the same protection working as intended.
Network and host hardening
-
Fix and firewall the ports. The registry listens on 1099 (
server_port); setserver.rmi.localporton the servers andclient.rmi.localporton the controller (which opens up to three ports from that base) so that the firewall can allow exactly those ports, and only between the controller and the servers. With SSL enabled, a fixedclient.rmi.localportbroke every remote start in a 5.6.3 test run; Distributed Testing shows the error and the alternative (leave it at 0 and allow the workers to reach the controller’s subnet). -
Use a private network for the controller-to-server traffic, separate from the network the load goes to.
-
Run the servers only for the test.
-Xon the controller, orserver.exitaftertest=trueon a server, makes the server exit after the test instead of waiting for the next plan. -
Run JMeter as an unprivileged user, with write access only to its own working directories.
-
The security manager. The manual describes enabling the Java security manager on distributed nodes (
-Djava.security.managerand ajava.policyfile insetenv.sh) to restrict what a plan can do. That mechanism is deprecated for removal since Java 17 (JEP 411) and permanently disabled in Java 24 (JEP 486), where enabling it at start-up is an error. On the Java 21 this guide recommends it still works, with a deprecation warning, but it has no future; network isolation and least-privilege accounts are the lasting controls.
The BeanShell server
The BeanShell server is a different thing from the BeanShell elements (sampler, pre-processor, assertion). When enabled, the BeanShell interpreter inside JMeter listens on two ports: an HTTP port and, on the next port, a telnet port. The best-practices chapter is unambiguous: there is no security; anyone who can connect to the port can issue any BeanShell command, which gives unrestricted access to the JMeter application and the host. Do not enable it unless the ports are protected against access, for example by a firewall.
| Property | Default | Meaning |
|---|---|---|
|
|
Non-zero starts the HTTP server on that port and the telnet server on the next one (for example 9000 and 9001). |
|
|
Initialisation file processed by the server. |
It is off by default; the rule is to keep it that way. A quick check of the properties files a generator uses:
grep -nE '^[[:space:]]*beanshell\.server\.port[[:space:]]*=' \
"$JMETER_HOME"/bin/jmeter.properties "$JMETER_HOME"/bin/user.properties *.properties
On a default 5.6.3 installation this prints nothing: the line in jmeter.properties is commented out
(#beanshell.server.port=9000). Any uncommented, non-zero value is a finding. If live inspection of a running test is
needed, use the CLI shutdown port commands (HeapDump, ThreadDump) or the Backend Listener described on
Real-time Monitoring with Backend Listener
instead.
The books still use BeanShell pre- and post-processors (Pro Apache JMeter ch. 3); the current manual recommends JSR223 elements with Groovy, see Scripting with JSR223 & Groovy.
Trusting .jmx files
The JMeter security model is stated on the project’s security page: JMeter executes the workload in the .jmx file,
which may include arbitrary code, so the model assumes you trust the .jmx input; even opening a .jmx file may in
some cases trigger code execution. Evaluating untrusted plans requires isolation that you provide.
In practice:
-
Treat a
.jmxfile like a script. Review changes to plans in pull requests the way code is reviewed, paying attention to JSR223 and BeanShell elements, OS Process Samplers and functions such as__groovy. -
Do not open a plan from an unknown source in the GUI on your workstation. Read the XML first, or open it in a disposable virtual machine or container with no credentials and no network access to anything that matters.
-
Load generators fetch plans from a trusted location only (the repository, a signed artefact), never from a shared upload folder.
Source: Security (Apache JMeter)
Keeping JMeter, Java and plugins updated
-
JMeter. The best-practices chapter asks users to use the latest version, to read the changes list of each release, and to "absolutely avoid" versions older than three versions before the last one. Verify each download with its SHA-512 checksum and PGP signature, as shown in Installation & Configuration.
-
Java. The getting-started chapter advises installing the latest minor version of your Java major version for security and performance reasons.
-
Security announcements. Vulnerabilities in JMeter are reported privately to
security@apache.org, fixed in a new release, and then announced publicly. At the time of writing the JMeter security page describes the model and the reporting process but does not list individual CVEs; read the changes page of each new release, and report a suspected vulnerability to the private list rather than in a public issue. -
Bundled libraries. JMeter ships many third-party jars in
lib/. Replacing them by hand is unsupported; take the next JMeter release instead. For 6.0,changes.xmlon master plans Java 17 as the minimum and upgrades several bundled libraries (for example Log4j 2.26.1 and Groovy 5.1.3), and fixes a CLI log message that wrongly reported keystore passwords as missing (PR 6372). These are planned, not released. -
Plugins. Plugins are updated separately from JMeter, through the Plugins Manager or your build. Pin their versions and review the update notes like any other dependency.
Judging third-party plugins
A plugin is a jar in lib/ext that runs inside the JMeter JVM with the same permissions as JMeter itself: it can read
the plan, the variables (secrets included), the file system and the network. jmeter-plugins.org is an independent
community catalogue, not an Apache project, and the Apache security process does not cover it. The checklist on
Plugins & Plugins Manager
(activity, maintainer and archive status, compatibility, licence, dependencies, download source, SNAPSHOT versions, a
core alternative) applies; the security reading of it is:
-
Prefer core. Every plugin you avoid is one less third-party code base on every generator.
-
Check the maintainer and the history. An archived project, or a catalogue id that changed hands (as happened to the gRPC Request plugin), deserves a second look at who now publishes the jar.
-
Check dependencies for known vulnerabilities. Old copies of common libraries inside a plugin are the usual problem; release notes that list CVE fixes show that the maintainer tracks them.
-
Pin versions and record checksums, so a rebuilt load generator gets exactly the jars that were reviewed.
-
Control what the Plugins Manager sends and fetches. Set
jpgc.repo.sendstats=falseto stop the usage statistics, and pointjpgc.repo.addressat an internal mirror when generators must not reach the internet. -
Install the same reviewed set on every node of a distributed test.
A pre-flight checklist
| Done | Check |
|---|---|
☐ |
Written approval names the target, window, peak load, stop conditions and contacts. |
☐ |
Hosting, CDN and third-party providers informed or replaced by stubs; their testing policies read. |
☐ |
Smoke run passed; load increases in steps. |
☐ |
No passwords, tokens or keys in the |
☐ |
Test accounts and synthetic data only. |
☐ |
Main results file in CSV without bodies or headers; errors-only listener for failed responses. |
☐ |
No Debug Sampler, View Results Tree or Functional Test Mode in the load run. |
☐ |
Recorder stopped; JMeter root CA removed from browsers; |
☐ |
Distributed nodes use RMI over SSL with a current keystore; RMI ports fixed and firewalled. |
☐ |
|
☐ |
JMeter, Java and plugins at reviewed, pinned, current versions. |
☐ |
Results stored with access control and a retention period. |
From the books to 5.6 to 6.0
| Era | Security-relevant state |
|---|---|
JMeter 2.11 to 3.0 (the books) |
Distributed testing over plain RMI (Pro Apache JMeter ch. 6, JMeter Cookbook ch. 5). Recording through the proxy and the WorkBench (Pro Apache JMeter ch. 4). BeanShell elements common in examples (Pro Apache JMeter ch. 3). |
JMeter 4.0 to 5.5 |
RMI over SSL becomes the default (4.0), with |
JMeter 5.6 to 5.6.3 |
Same model. The security page states the trust-the- |
JMeter 6.0 (planned) |
Per |
Pitfalls
-
"It’s only staging." Staging often shares a database cluster, network link, identity provider or third-party sandbox with production. Agree the test as if it were production.
-
Forgetting the generator’s side. Load generators in the cloud are bound by their provider’s testing policy too.
-
Real credentials in recordings. The recorder drops the
Authorizationheader but not the login body. -
-Jfor secrets. Convenient, and visible inpsand shell history. -
A Debug Sampler left in the plan. It copies every variable, secrets included, into a response that a listener may save.
-
Uploading the whole results folder as a CI artefact. Error bodies and logs go with it; upload the dashboard and the CSV, and keep error bodies in a restricted location.
-
server.rmi.ssl.disable=truecopied from an old tutorial. Create the keystore instead. -
An expired RMI keystore. The default script creates keys valid for 7 days; regenerate before each campaign rather than switching SSL off.
-
A trusted JMeter CA left in the everyday browser for months, or a
proxyserver.jkscopied into a Docker image. -
Opening a
.jmxfrom an unknown source in the GUI. The security model assumes plans are trusted.
References
-
Security (Apache JMeter): the security model (trusted
.jmxinput), the security manager recommendation for distributed use, and the private reporting process. -
Best Practices (Apache JMeter User Manual): using the latest version, the BeanShell server, parameterising tests.
-
Remote Testing (Apache JMeter User Manual): RMI over SSL,
create-rmi-keystore.sh, ports, the security manager. -
Distributed Testing Step by Step (Apache JMeter User Manual).
-
Component Reference (Apache JMeter User Manual): HTTP(S) Test Script Recorder certificates, HTTP Authorization Manager and the other fields "stored unencrypted in the test plan", Debug Sampler, View Results Tree.
-
Properties Reference (Apache JMeter User Manual): RMI SSL, BeanShell, recorder certificate and results-file properties.
-
Elements of a Test Plan (Apache JMeter User Manual): Functional Test Mode.
-
Getting Started (Apache JMeter User Manual): Java version advice and command-line options.
-
Functions (Apache JMeter User Manual):
__Pand__groovy. -
Download Apache JMeter: checksums, signatures and KEYS.
-
changes.xml on master (apache/jmeter): planned 6.0 changes.
-
JMeter Plugins Manager (JMeter Plugins wiki) and JMeter Plugins repository catalogue.
-
JEP 411: Deprecate the Security Manager for Removal and JEP 486: Permanently Disable the Security Manager.
-
Amazon EC2 Testing Policy: an example of a provider’s rules for stress tests and DDoS simulations.
-
Sai Matam and Jagdeep Jain, Pro Apache JMeter, Apress, 2017: chapter 3 (BeanShell elements), chapter 4 (recording), chapter 6 (distributed testing).
-
Bayo Erinle, JMeter Cookbook, Packt, 2014: chapter 5 (distributed testing).