JEP 536: JFR In-Process Data Redaction
Summary
Enhance JDK Flight Recorder (JFR) to redact command-line arguments and the initial values of environment variables and system properties in recordings. Redact this data before it leaves the process, so that sensitive information does not leak.
Motivation
JFR is a low-overhead diagnostics framework integrated into the HotSpot JVM. It writes information about the runtime and the application into timestamped events in a recording file, for later analysis by tools such as the jfr command and JDK Mission Control.
JFR recording files typically include events that report command-line arguments and the values of environment variables and system properties, so that you can see how the process was started and configured. These events can therefore contain sensitive data, such as secrets in command-line arguments, access tokens in environment variables, and passwords in system properties. Today, this data appears verbatim in recording files, which risks leaking sensitive information when recordings are shared, archived, or included in support cases.
For example, you might start an application with JFR enabled like so:
$ export ACCESS_TOKEN=SECRET_TOKEN
$ java -XX:StartFlightRecording:filename=dump.jfr \
-Xmx2G \
-Djavax.net.ssl.keyStorePassword=SECRET_PASSWORD \
-jar application.jar \
--dbpassword ANOTHER_SECRET_PASSWORD
The resulting recording file dump.jfr contains events that reveal all three of the secret values:
- A
jdk.InitialEnvironmentVariableevent records the value of theACCESS_TOKENenvironment variable, - A
jdk.InitialSystemPropertyevent records the value of thejavax.net.ssl.keyStorePasswordsystem property, and - A
jdk.JVMInformationevent records the argument passed to the application’s--dbpasswordcommand-line option.
In-process data redaction would prevent this leakage while preserving non-sensitive information needed for troubleshooting, such as the maximum heap size (-Xmx2G).
Description
JFR will now redact many kinds of sensitive information by default, without any additional configuration.
You can explicitly select the information that JFR should redact via new sub-options of the existing command-line option -XX:FlightRecorderOptions. Each sub-option specifies one or more filters that select the command-line arguments, environment variables, and system properties to be redacted.
-
The
redact-argumentsub-option specifies a filter list for command-line arguments. If one of the filters matches an argument, the argument is redacted. -
The
redact-keysub-option specifies a filter list for key-value pairs in the form of environment variables and system properties. If one of the filters matches a key, the associated value is redacted.
Matching is case-insensitive. Filters use glob patterns, where * and ? are wildcards. If a filter matches an argument or a key, the argument or the key’s value is recorded in the event as [REDACTED]. Multiple filters are separated with semicolons (;), and are evaluated in the given order. When a filter matches an argument, the matched argument is redacted and evaluation continues with the next argument. Multiple sub-options of -XX:FlightRecorderOptions are separated by commas.
For example, to redact any environment variable or system property named confidential or CONFIDENTIAL, plus any command-line argument that looks like a URL containing a username and password (i.e., username:password@host), use:
$ export CONFIDENTIAL=SOME_SECRET
$ java -XX:FlightRecorderOptions:'redact-key=confidential,redact-argument=https://*:*@*' \
-XX:StartFlightRecording:filename=dump.jfr \
-Dconfidential=ANOTHER_SECRET \
-jar application.jar https://john:YET_ANOTHER_SECRET@example.com/login --verbose
To verify that sensitive information has been redacted, use jfr print:
$ jfr print \
--events InitialSystemProperty,JVMInformation,StringFlag,InitialEnvironmentVariable \
dump.jfr
jdk.JVMInformation {
startTime = 17:39:02.196 (2026年02月15日)
jvmVersion = "Java HotSpot(TM) 64-Bit Server VM"
jvmArguments = "-Dconfidential=[REDACTED]
-XX:FlightRecorderOptions:redact-key=confidential,redact-argument=[REDACTED]
-XX:StartFlightRecording:filename=dump.jfr"
jvmFlags = "N/A"
javaArguments = "-jar application.jar [REDACTED] --verbose"
jvmStartTime = 17:39:02.050 (2026年02月15日)
pid = 43671
}
jdk.InitialSystemProperty {
startTime = 17:39:02.196 (2026年02月15日)
key = "confidential"
value = "[REDACTED]"
}
jdk.InitialSystemProperty {
startTime = 17:39:02.196 (2026年02月15日)
key = "sun.java.command"
value = "-jar application.jar [REDACTED] --verbose"
}
jdk.StringFlag {
startTime = 17:39:02.196 (2026年02月15日)
name = "FlightRecorderOptions"
value = "redact-key=confidential,redact-argument=[REDACTED]"
origin = "Command line"
}
jdk.InitialEnvironmentVariable {
startTime = 17:39:02.244 (2026年02月15日)
key = "CONFIDENTIAL"
value = "[REDACTED]"
}
To debug redact-argument and redact-key filter matching, start the JVM with the command-line option -Xlog:jfr+redact=debug to identify which command-line arguments, environment variables, and system properties are redacted.
Matching multiple command-line arguments
Sometimes, a command-line argument names an option whose value is expressed in the next argument; for example, --password SENSITIVE. Redacting --password alone would not be sufficient, and matching against SENSITIVE itself would require revealing something about SENSITIVE in the filter, thereby weakening its confidentiality.
To handle this, a filter can match a sequence of command-line arguments, separated by whitespace. For example, this filter redacts any argument named --password, together with the next argument:
$ java -XX:FlightRecorderOptions:'redact-argument=--password *' ...
To match three arguments, add another space and another asterisk:
$ java -XX:FlightRecorderOptions:'redact-argument=--password * *' ...
Loading filters from a file
To avoid overly long command lines, JFR can load redaction filters from a file. This enables filter lists to be reused across deployments, and allows filters to be updated without changing JVM startup options. Filter files contain one filter per line; trailing whitespace is ignored.
To specify a filter file on the command line, prefix the filename with @:
$ java '-XX:FlightRecorderOptions:redact-argument=@args.txt,redact-key=@keys.txt' ...
JFR reads filter files at JVM startup. If a file cannot be read, the JVM prints an error message identifying the file and then exits. To check that a filter file is loaded successfully, use -Xlog:jfr+redact=debug.
The same filter file may be used for both the redact-argument and redact-key sub-options, if appropriate.
Default filters
If the redact-key sub-option is not specified, JFR uses this default filter list for key-value pairs:
*api*key*
*auth*
*client*secret*
*credential*
*jaas*config*
*passphrase*
*passwd*
*password*
*private*key*
*pwd*
*secret*
*token*
If the redact-argument sub-option is not specified, JFR uses this default filter list for command-line arguments:
-*api*key *
-*client*secret *
-*credential *
-*jaas*config *
-*passphrase *
-*passwd *
-*password *
-*private*key *
-*pwd *
-*secret *
-*token *
*api*key*
*client*secret*
*credential*
*jaas*config*
*passphrase*
*passwd*
*password*
*private*key*
*pwd*
*secret*
*token*
The default filter list for redact-argument is similar to that for redact-key, except that
-
It includes filters to match multiple arguments; e.g.,
-*password *matches both-password SECRETand--password SECRET; and -
It omits the
*auth*filter, to avoid matching words such asauthor.
Returning to our initial example:
$ export ACCESS_TOKEN=SECRET_TOKEN
$ java -XX:StartFlightRecording:filename=dump.jfr \
-Xmx2G \
-Djavax.net.ssl.keyStorePassword=SECRET_PASSWORD \
-jar application.jar \
--dbpassword ANOTHER_SECRET_PASSWORD
JFR redacts:
- The value of the environment variable
ACCESS_TOKENvia the default filter*token*, - The value of the system property
javax.net.ssl.keyStorePasswordvia the default filter*password*, and - The command-line option
--dbpasswordand its argument,ANOTHER_SECRET_PASSWORD, via the default filter-*password *.
Adding to the default filters
To include the default filters when you specify your own filters, prefix the first filter with +:
$ java -XX:FlightRecorderOptions:'redact-key=+confidential;secret;@keys.txt' ...
Disabling redaction
To disable all redaction, specify none:
$ java -XX:FlightRecorderOptions:'redact-argument=none' ...
Syntax
The syntax of filter lists is:
filter-list ::= 'none' | filters
filters ::= ['+'] filter (';' filter)*
filter ::= expression | '@' filename
glob-pattern ::= characters (including '*' and '?' wildcards), matched case-insensitively
For redact-key:
expression ::= glob-pattern
For redact-argument:
expression ::= glob-pattern (' ' glob-pattern)*
Alternatives
-
Use the existing jfr scrub command to manually remove events that contain sensitive data from recording files.
This is repetitive and error-prone. Also, in normal operation, event data is written to a temporary directory before it is written to the recording file. If the JVM crashes, unredacted event data could be left behind in that directory. If recording data is streamed, using FlightRecorderMXBean or RemoteRecordingStream, unredacted event data could leave the host.
-
Disable specific events in order to prevent sensitive data from being captured. For example,
$ java -XX:StartFlightRecording:'jdk.InitialEnvironmentVariable#enabled=false' ...would disable the recording of environment-variable values.
This is cumbersome to configure and could remove the values of non-sensitive environment variables which are needed for troubleshooting.
Additionally, the person who configures the JVM command-line options might not be aware that sensitive data could be recorded, so they will not know to disable specific events. The default redaction filters will remove many kinds of sensitive data without advance configuration.
-
Filter data using regular expressions.
Regex-based filtering could be implemented in the JVM via the C++ regular expression library, but that library can throw exceptions, which are prohibited in HotSpot.
Alternatively, regex-based filtering could be implemented in Java code via the
java.util.regexAPI, but that would increase startup time. It would also complicate extending redaction filters to new events in situations in which an upcall from the JVM to Java is not possible.Regardless of implementation choice, experience suggests that the expressive power of regular expressions is rarely necessary.
-
Disable redaction by default so that fields with sensitive information are not replaced by
[REDACTED]unless redaction is enabled on the command line.Sensitive data passed from the shell is rarely needed for troubleshooting. When it is, the
[REDACTED]placeholder tells you that redaction is in effect; you can consult the documentation learn how to disable it. Unintentional leakage of sensitive data is the greater concern, since the damage that it causes may be irreversible.Furthermore, as noted earlier, the person who configures the JVM command-line options might not be aware that sensitive data could be recorded. If redaction were disabled by default then sensitive data could leak if someone else later connects to the application via JDK Mission Control or starts a recording via the
jcmdtool.
Risks and Assumptions
In the default redaction mode, JFR recordings may differ from those created with previous releases since they will contain [REDACTED] in affected fields. To revert to the past behavior, specify:
$ java -XX:FlightRecorderOptions:'redact-argument=none,redact-key=none' ...