How does Spring Boot prevent /env and /configprops from leaking secrets, and how do you control value masking?
answer
- default masked keys: password/secret/key/token/credentials
- show-values: NEVER (default) / ALWAYS / WHEN_AUTHORIZED
- WHEN_AUTHORIZED pairs with endpoint.env.roles
- SanitizingFunction bean on SanitizableData
- keys-to-sanitize REPLACES defaults — footgun
basics
~20 sEven for authorized users, /env and /configprops mask sensitive values. By default keys like password, secret, key, token and credentials are shown as '******', and since Boot 3 all values are hidden unless you set show-values to ALWAYS or WHEN_AUTHORIZED. You can add custom SanitizingFunction beans.
solid answer
~40 sActuator sanitizes value output on /env and /configprops so a secret doesn't leak even to an authenticated admin. Historically Spring Boot masked keys matching a default pattern (password, secret, key, token, .*credentials.*, vcap_services, sun.java.command) shown as '******'. In Spring Boot 3 the model changed: values are hidden entirely by default and you opt in via management.endpoint.env.show-values and management.endpoint.configprops.show-values with NEVER / ALWAYS / WHEN_AUTHORIZED. WHEN_AUTHORIZED reveals real values only to callers who meet the endpoint's roles (management.endpoint.env.roles). For custom rules you register SanitizingFunction beans that inspect the SanitizableData key/value and mask conditionally. Rely on this even behind auth — defense in depth means logs, screenshots, and over-broad admin access shouldn't expose raw secrets.
code
java · 15 lines// application.yml
// management.endpoint.env.show-values: when-authorized
// management.endpoint.env.roles: ACTUATOR_ADMIN
// management.endpoint.configprops.show-values: never
@Bean
SanitizingFunction maskAcmeSecrets() {
return data -> {
String key = data.getKey();
if (key != null && key.toLowerCase().contains("acme.token")) {
return data.withValue("******"); // additive rule, keeps defaults
}
return data; // unchanged -> other functions/defaults still apply
};
}go deeper
Should know /env and /configprops mask secret-looking keys.
Should name show-values NEVER/ALWAYS/WHEN_AUTHORIZED and the default masked keys.
Should combine WHEN_AUTHORIZED + roles and add SanitizingFunction beans, and know the keys-to-sanitize override footgun.
Should treat masking as data-minimization defense-in-depth independent of access control and audit exposure.
**The specific risk.** `/actuator/env` renders the whole Spring `Environment`; `/actuator/configprops` renders every `@ConfigurationProperties` bean with its currently bound values. Without masking, that includes `spring.datasource.password`, cloud API keys, signing secrets — visible to anyone who can reach the endpoint. **Layer 1 — key-based sanitization (always on).** Actuator ships default sanitization: property **keys** matching known-sensitive patterns are replaced with `******` regardless of who calls. The historical default set includes `password`, `secret`, `key`, `token`, anything containing `credentials`, `vcap_services`, and `sun.java.command`. This is applied by `Sanitizer`, which operates on `SanitizableData` (holds the key, the raw value, and the property source). **Layer 2 — show-values policy (Spring Boot 3+).** Boot 3 tightened defaults: rather than showing non-sensitive values in clear text and masking only matched keys, the endpoints gained an explicit visibility switch: - `management.endpoint.env.show-values` and `management.endpoint.configprops.show-values` accept **NEVER** (default — mask everything), **ALWAYS** (show all, still applying key-based sanitization for known secrets), or **WHEN_AUTHORIZED** (show values only to callers who satisfy the endpoint's configured roles). - With `WHEN_AUTHORIZED`, you pair it with `management.endpoint.env.roles=ACTUATOR_ADMIN` (and the equivalent for health details, `management.endpoint.health.roles`). An authenticated but under-privileged caller still sees `******`. **Layer 3 — custom SanitizingFunction beans.** Register `@Bean SanitizingFunction` to add project-specific rules — e.g., mask any key under a `com.acme.` prefix, or partially mask (show last 4 chars). Each function receives `SanitizableData` and returns it with `.withValue(masked)` or unchanged. Multiple functions compose. In older Boot you could instead set `management.endpoint.env.keys-to-sanitize` (a regex list) — but note that **setting** `keys-to-sanitize` **replaces** the defaults, so you can accidentally unmask `password` if you provide a list without re-including it. Prefer additive `SanitizingFunction` beans. **Gotchas:** - Sanitization is about **display**, not access. If the endpoint itself is unauthenticated, masking still hides secret values, but non-secret config and structure leak. - `keys-to-sanitize` override footgun: replacing the default list drops built-in patterns. - `show-values=ALWAYS` still runs key sanitization, so known secrets stay masked — but a mis-named key (`db_pass` instead of `password`) may slip through; add a `SanitizingFunction`. - Health detail leakage is a sibling concern: `management.endpoint.health.show-details` (never / when-authorized / always) controls whether component-level health (DB up/down, disk space) is shown. **When to use:** Keep `show-values=NEVER` in production unless an operator genuinely needs values; if they do, use `WHEN_AUTHORIZED` + roles, never `ALWAYS`. Add `SanitizingFunction` for any custom secret-bearing keys.
- If /env is behind an admin role, why still sanitize values?Defense in depth. Admin access is broader than any single secret; sanitized output means the secret doesn't end up in an operator's browser history, a shared screenshot, a proxy log, or an over-scoped audit. Access control and data minimization are separate controls.
- What's the risk of setting management.endpoint.env.keys-to-sanitize?It replaces the default sensitive-key list rather than adding to it, so if your list omits 'password' or 'secret' those become visible. Prefer registering additive SanitizingFunction beans.
saying these in an interview costs you the question
- Claiming /env values are always shown in clear text (Boot 3 default is NEVER)
- Thinking authentication alone removes the need to mask values
- Assuming keys-to-sanitize is additive (it overrides defaults)
- Setting show-values=ALWAYS in production for convenience