JEP draft: JFR In-Process Data Redaction

OwnerErik Gahlin
TypeFeature
ScopeJDK
StatusSubmitted
Componenthotspot / jfr
EffortM
DurationM
Reviewed byMarkus Grönlund, Vladimir Kozlov
Created2025/11/30 02:51
Updated2026/04/02 13:38
Issue8372760

Summary

Add redaction to JDK Flight Recorder (JFR) to keep sensitive data out of recordings. This feature covers command-line arguments and the values of environment variables and system properties specified at startup. To prevent sensitive data from leaking, JFR redacts it before it leaves the process.

Motivation

JFR is a low-overhead diagnostics framework integrated into the Java Virtual Machine (JVM). It captures information about the runtime and the application, and it stores it as timestamped events in a recording file that tools such as the the jfr command and JDK Mission Control can analyze later. Recordings typically include events that contain environment variables, system properties, and command-line arguments so users can see how the process was started and configured.

These events can contain sensitive data, such as passwords in system properties, tokens in environment variables, and secrets passed as command-line arguments. Today, this data appears verbatim in recordings, which creates risk when recordings are shared, archived, or attached to support cases.

For example, a user may start their application with JFR enabled like this, not realizing what ends up in the recording file dump.jfr:

$ export ACCESS_TOKEN=secret_token_value
$ java @options.txt 
    -XX:StartFlightRecording:filename=dump.jfr
    -Xmx2G
    -jar application.jar
    --dbpassword secret_password

@options.txt is an argument file containing the following option:

-Djavax.net.ssl.keyStorePassword=secret_password

The jdk.InitialEnvironmentVariable event records the ACCESS_TOKEN value. The jdk.InitialSystemProperty and jdk.JVMInformation events store the value of javax.net.ssl.keyStorePassword and the argument passed to --dbpassword.

In-process redaction prevents this while preserving non-sensitive information needed for troubleshooting, such as the heap size configuration (-Xmx2G).

Description

In the scenario described in the Motivation section, sensitive information is redacted by default, and users do not need to configure anything.

However, to explain the feature, it is easiest to use an example where this is not the case and show how to use the two new sub-options in -XX:FlightRecorderOptions. These options control how JFR filters arguments and properties so that recorded events do not store sensitive content.

Matching is case-insensitive. Filters use glob patterns, where * and ? are wildcards. If a filter matches a key or an argument, the corresponding value or argument stored in the event is replaced with [REDACTED]. Sub-options of -XX:FlightRecorderOptions are comma-separated. Within redact-key and redact-argument, multiple filters are separated with semicolons (;) and evaluated in the order they are specified. When a filter matches a command-line argument, the matched argument is redacted and evaluation continues with the next argument.

Example

To redact any environment variable or system property named confidential, plus any command-line argument that looks like a URL containing username:password@host, use:

$ export confidential=secret
$ java
    '-XX:FlightRecorderOptions:redact-key=confidential,redact-argument=https://*:*@*'
    -Dconfidential=secret
    -XX:StartFlightRecording:filename=dump.jfr
    -jar application.jar https://john:secret@example.com/login --verbose

To verify that sensitive information has been removed, 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 filter matching, start the JVM with -Xlog:jfr+redact=debug to identify which environment variables, system properties, or command-line arguments are redacted.

Matching a following argument

Sometimes, sensitive information in command-line options is passed as a value after an option, for example, --password <sensitive>. Matching against --passwordalone would not be sufficient, and matching only against` would require the sensitive information to be known, which is not possible in a generic, predefined filter. To remedy this, multiple arguments can be matched by inserting whitespace between the arguments.

For example, the following filter redacts all arguments named --password and any argument that follows:

$ java '-XX:FlightRecorderOptions:redact-argument=--password *' ...

To match more than two arguments, add another space, for example: --password * *.

Loading filters from a file

Filters can be loaded from a file to avoid overly long command lines. This enables reuse of the same filter set across deployments and allows redaction rules to be updated without changing JVM startup options. Filters are stored with one filter per line, and any trailing whitespace at the end of a line is removed.

To reference a file on the command line, prefix the filename with @.

$ java '-XX:FlightRecorderOptions:redact-argument=@redact-arguments.txt,redact-key=@redact-keys.txt' ...

Filter files are read at startup. If a file cannot be read, the JVM fails to start and prints an error message naming the unreadable file. To log that a redaction file is loaded successfully, use -Xlog:jfr+redact=debug.

The same file may be used for both the redact-argument and redact-key options, if appropriate.

Defaults, adding to defaults, and disabling

By default, JFR applies a built-in set of filters when redact-key or redact-argument are not specified.

The default filters for redact-key are:

*api*key*
*auth*
*client*secret*
*credential*
*jaas*config*
*jwt*
*passphrase*
*passwd*
*password*
*private*key*
*pwd*
*secret*
*token*

The default filters for redact-argument are similar to those for redact-key, but the *auth* filter is omitted to avoid matching words like author. Filters are also included to match a following argument. The filter prefix -* matches command-line options that start with - or --, for example, -password or --password.

-*api*key *
-*client*secret *
-*credential *
-*jaas*config *
-*jwt *
-*passphrase *
-*passwd *
-*password *
-*private*key *
-*pwd *
-*secret *
-*token *
*api*key*
*client*secret*
*credential*
*jaas*config*
*passphrase*
*passwd*
*password*
*private*key*
*pwd*
*secret*
*token*

Returning to the scenario described in the Motivation section, this means that ACCESS_TOKEN is redacted by the default filter *token*, javax.net.ssl.keyStorePassword is matched by the *password* filter, and --dbpassword secret_password is redacted via -*password *.

To add filters on top of the defaults, prefix the first filter with +. Without +, the specified filters replace the defaults. To disable redaction for an option, use none.

$ java '-XX:FlightRecorderOptions:redact-key=+confidential;secret;@secret-keys.txt,redact-argument=none' ...

Syntax

The following grammar defines the option value syntax.

option-value ::= '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

Risks and Assumptions

With defaults enabled, recordings may differ from earlier releases by showing [REDACTED] in affected fields. To preserve prior behavior, users can specify:

-XX:FlightRecorderOptions:redact-argument=none,redact-key=none