How would you safely expose these diagnostic endpoints in production, given heapdump/threaddump can leak sensitive data?
answer
- only health public; never exposure.include=* in prod
- separate management.server.port + address (internal)
- Spring Security EndpointRequest.toAnyEndpoint() + role
- heapdump = secret exfil; capture from replica / OOM flag
- management.endpoint.heapdump.access=none until needed
basics
~10 sDon't expose them publicly. Keep only health public, put diagnostic endpoints behind authentication/authorization, ideally on a separate internal management port, and restrict access to operators. Treat any heap dump as a secret.
solid answer
~50 sBecause heapdump externalizes raw memory (secrets, tokens, PII) and threaddump reveals internals, I treat these as privileged operator tools, not public endpoints. In production I: keep only /actuator/health (and maybe info) web-exposed for load balancers; move management to a separate port via management.server.port bound to an internal interface / management.server.address so the actuator isn't reachable from the public listener; secure all actuator routes with Spring Security using EndpointRequest.toAnyEndpoint() requiring an operator role; and never add sensitive headers to httpexchanges recording. I gate the network too — actuator port reachable only from the ops network / mesh, not the internet. For heap dumps specifically I prefer capturing from a drained replica or via -XX:+HeapDumpOnOutOfMemoryError rather than pulling live under load, and I handle any downloaded .hprof as a secret artifact (encrypted at rest, deleted after analysis). I also consider disabling heapdump entirely (management.endpoint.heapdump.access=none) unless needed.
code
java · 18 linesimport static org.springframework.security.config.Customizer.withDefaults;
import org.springframework.boot.actuate.autoconfigure.security.servlet.EndpointRequest;
import org.springframework.boot.actuate.health.HealthEndpoint;
import org.springframework.context.annotation.Bean;
import org.springframework.security.web.SecurityFilterChain;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
@Bean
SecurityFilterChain actuatorSecurity(HttpSecurity http) throws Exception {
http.securityMatcher(EndpointRequest.toAnyEndpoint())
.authorizeHttpRequests(auth -> auth
// health/liveness/readiness open for probes
.requestMatchers(EndpointRequest.to(HealthEndpoint.class)).permitAll()
// everything else (threaddump, heapdump, httpexchanges) requires operator role
.anyRequest().hasRole("ACTUATOR"))
.httpBasic(withDefaults());
return http.build();
}go deeper
Know these endpoints are sensitive and shouldn't be public.
Restrict exposure to health and secure the rest with Spring Security.
Use a separate management port + EndpointRequest-based authorization and per-endpoint access control.
Design the full defense-in-depth posture (network isolation, auth, per-endpoint access, heap-dump lifecycle/DoS, auditing) and articulate the threat model.
**Threat model.** These endpoints are qualitatively more dangerous than health/metrics: - **heapdump** streams the raw heap — every String, token, password, session, key currently in memory. A single unauthenticated GET is a full credential/PII exfiltration. - **threaddump** exposes stack traces, class/method names, and internal structure — useful reconnaissance for an attacker and occasionally leaks argument-ish detail. - **httpexchanges** can hold request/response data (and, if misconfigured to include COOKIE_HEADERS/AUTHORIZATION_HEADER, live credentials). **Layered hardening.** 1. **Minimal exposure.** Expose over the web only what infra needs: `management.endpoints.web.exposure.include=health` (plus `info`/`prometheus` if scraped). Do **not** use `*` in production. Diagnostic endpoints stay unexposed (or exposed only on the management port below). 2. **Separate management port.** Set `management.server.port` to a different port from the app, and bind it to an internal interface with `management.server.address` (e.g. a private IP). Now the public HTTP listener physically cannot serve `/actuator/heapdump`; only something on the internal network can reach the management port. This is the single most effective control. 3. **AuthN/AuthZ.** Secure actuator routes with Spring Security. Use `EndpointRequest.toAnyEndpoint()` (optionally `.excluding(HealthEndpoint.class)`) and require an operator authority: ```java http.securityMatcher(EndpointRequest.toAnyEndpoint()) .authorizeHttpRequests(a -> a.anyRequest().hasRole("ACTUATOR")) .httpBasic(withDefaults()); ``` Health can stay permitted for probes. Even behind an internal port, require auth (defense in depth). 4. **Per-endpoint access control.** Spring Boot 3.4+ supports `management.endpoint.<id>.access` (`none`/`read-only`/`unrestricted`; older Boot used `.enabled`). Disable what you don't need — e.g. `management.endpoint.heapdump.access=none` unless an incident requires it, then enable temporarily. 5. **Network / mesh.** Restrict the management port with firewall rules, security groups, NetworkPolicies, or a service mesh so only the ops jump-host / observability plane can reach it. Kubernetes: put actuator on a port that's not in the public Service, or gate with NetworkPolicy. 6. **httpexchanges hygiene.** Never include COOKIE_HEADERS/AUTHORIZATION_HEADER in `management.httpexchanges.recording.include`; keep the buffer small; prefer proper tracing/APM for real observability. **Heap-dump operational discipline.** Pulling a live heap dump on a hot node causes a stop-the-world pause proportional to heap size and produces a multi-GB file. Prefer: capture from a **drained/replica** instance, or rely on `-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=...` so the JVM writes one at the failure moment without you loading the live node. Treat the resulting `.hprof` as a **secret artifact**: transfer over TLS, store encrypted, restrict access, and delete after MAT analysis. Sanitize/redact is effectively impossible, so control the file's lifecycle instead. **Auditing & rate limiting.** Log and alert on access to these endpoints; consider rate-limiting heapdump to prevent disk-fill / DoS. Treat any access outside a known incident as suspicious. **Summary stance.** Public: `health` only. Internal & authenticated: `threaddump`, `httpexchanges`. On-demand & tightly controlled: `heapdump`. The default of 'only health web-exposed' exists for exactly this reason — don't override it carelessly with `exposure.include=*`.
- Why is putting actuator on a separate management port often more valuable than authentication alone?Binding management.server.port/address to an internal interface means the public listener physically cannot serve heapdump/threaddump — an internet client can't even reach the route. It removes the endpoint from the public attack surface entirely, and you still add auth on top for defense in depth.
- What's a safer way to obtain a heap dump in production than calling the endpoint on a live hot node?Capture it from a drained/replica instance out of rotation, or configure -XX:+HeapDumpOnOutOfMemoryError so the JVM writes an .hprof automatically at OOM — avoiding a stop-the-world live dump under load — then handle the file as a secret.
- Why should you never add AUTHORIZATION_HEADER or COOKIE_HEADERS to httpexchanges recording?Those headers carry live credentials/session tokens; recording them stores exploitable secrets in the in-memory buffer, visible to anyone who can read the endpoint — a credential-leak risk with no upside for debugging.
saying these in an interview costs you the question
- Using management.endpoints.web.exposure.include=* in production
- Exposing heapdump on the public port with no auth 'because it's handy'
- Believing you can redact secrets out of a heap dump
- Thinking network isolation replaces the need for authentication (skip defense in depth)