An exposed Spring Boot Actuator endpoint can hand an attacker a heap dump full of live secrets, the application's whole configuration, or a way to change its behaviour at runtime, all without exploiting a single bug. Actuator is the production-readiness module that gives Spring Boot applications health checks, metrics and diagnostics, and most of what it offers is an administrative API by another name. This guide goes deeper than the Actuator section of our Java and Spring guide: it explains how endpoint access, exposure and security interact in current Spring Boot, who should be allowed to call which endpoint, how monitoring tools and Kubernetes probes should authenticate, what to log, and a hardening baseline with rollout steps. It is written for application security engineers, platform teams and Spring developers.
Key takeaways
- Three settings decide exposure, not one. An endpoint is reachable only when access permits it, it is exposed over HTTP or JMX, and the security chain lets the caller through. Teams usually change one and forget the other two.
- heapdump, env and configprops are credential stores. A heap dump contains whatever is in memory, including decrypted secrets and tokens, so treat it like a vault export and keep it off any reachable port.
- A custom SecurityFilterChain switches off Boot's protection. Once you define your own chain, Spring Boot backs off entirely, so you must add an explicit chain for
EndpointRequest.toAnyEndpoint()or Actuator becomes as open as your rules allow. - Write operations are the real admin rights.
loggers,sessions,shutdownand Spring Cloud'sPOST /actuator/envandrefreshchange a running application. Cap everything at read-only unless a named operator needs more. - Monitoring callers are non-human identities. Prometheus scrapers, Spring Boot Admin and probe agents need their own scoped credentials or network path, not a shared admin password baked into every service.
How identity and access work in Spring Boot Actuator
Actuator does not have its own user store. It relies on three independent layers, and the current Spring Boot reference documentation describes each one separately. An endpoint is "available" only when access is permitted and it is exposed; Spring Security then decides who may call it.
| Layer | Property or mechanism | Default | What it controls |
|---|---|---|---|
| Access | management.endpoint.<id>.access (unrestricted, read-only, none) | Unrestricted for every endpoint except shutdown and heapdump | Whether the endpoint exists in the application context at all and which operations it allows |
| Access cap | management.endpoints.access.max-permitted | Not set | An application-wide ceiling that overrides per-endpoint settings; read-only blocks every write operation |
| Opt-in mode | management.endpoints.access.default=none | Not set | Makes access opt-in, so each endpoint must be enabled by name |
| Exposure | management.endpoints.web.exposure.include and .exclude (and the jmx equivalents) | Only health over HTTP and JMX | Which available endpoints are remotely reachable; exclude wins over include |
| Authentication and authorisation | Spring Security SecurityFilterChain with EndpointRequest matchers | If Spring Security is present and you define no chain, every endpoint except /health requires authentication | Who may call an exposed endpoint, and with which role |
| Value disclosure | management.endpoint.env.show-values (also configprops, quartz) and .roles | never: values replaced with ****** | Whether property values are shown unsanitised, and to whom |
| Network | management.server.port, management.server.address, management.server.ssl.* | Same port as the application | Whether management traffic shares the public listener |
Two details catch experienced teams. First, read access is defined per endpoint type: for @Endpoint and @WebEndpoint it means read operations, and for servlet endpoints it means GET and HEAD, so a cap of read-only still allows a GET /actuator/heapdump if heapdump has been made accessible. Second, for JMX the documentation states that all users are always treated as authorised for sanitised values, so show-values: when-authorized gives no protection over JMX. Any remote JMX port or JMX-over-HTTP bridge must be secured at the network and JVM level.
Admin roles and privileged access
Classify endpoints by what they reveal and what they can change, then map each class to a role. The table reflects the endpoint descriptions in the Spring Boot reference; the risk column is our assessment.
| Endpoint | What it does | Risk if reachable by an attacker | Suggested role |
|---|---|---|---|
heapdump | Returns an HPROF (HotSpot) or PHD (OpenJ9) heap dump | Critical: in-memory secrets, OAuth tokens, database passwords, session IDs and request data | Not exposed over HTTP; break-glass only on an isolated port |
env, configprops | Lists environment and @ConfigurationProperties values | High: property names reveal architecture; unsanitised values reveal credentials | Operator role, values never shown |
threaddump, logfile, httpexchanges | Thread stacks, the log file (supports HTTP Range), last 100 HTTP exchanges | High: logs and exchanges often carry headers, tokens and personal data | Operator role |
loggers | Shows and modifies log levels | High as a write: switching a package to DEBUG or TRACE can start writing secrets and payloads to logs | Read for operators; write for a named on-call role |
sessions | Retrieves and deletes Spring Session sessions | High: session enumeration and forced logouts | Write restricted to security operations |
shutdown | Graceful shutdown (jar packaging, disabled by default) | Availability | Leave inaccessible; use the orchestrator |
beans, conditions, mappings, scheduledtasks, startup | Internal structure, every request mapping and scheduled job | Medium: a map of hidden routes and libraries for targeting | Developer or operator role, non-production preferred |
metrics, prometheus | Recorded metrics | Low to medium: tag values can leak user IDs or URLs | Scraper identity only |
health, info | Status; build and git details by default | Low if details are hidden; info.git.mode=full discloses the full git.properties | Public status only, details to an authenticated role |
- Use a dedicated role: the Spring Boot sample secures
EndpointRequest.toAnyEndpoint()withhasRole("ENDPOINT_ADMIN"). Keep that role separate from application administrators so a compromised business admin account does not inherit heap dumps. - Split read and write: combine
max-permitted: read-onlyin production with per-endpoint grants, and only lift the cap in a change window for a named operator. - Restrict unsanitised values by role: if operators genuinely need values, set
show-values: when-authorizedwithrolesset. Withoutroles, the documentation says any authenticated user is authorised, which on a single sign-on application means every employee. - Keep CSRF on: Spring Security's CSRF protection is on by default and blocks POST, PUT and DELETE Actuator calls from browsers. Disable it only on a management chain used solely by non-browser clients.
Our Spring Security Configuration Guide covers filter chain ordering and matcher pitfalls in depth. See the Java and Spring Security Guide for the wider Spring attack surface.
Integrations, API tokens and service accounts
Most Actuator traffic in production comes from machines: metrics scrapers, Kubernetes kubelets, Spring Boot Admin servers, APM agents and deployment tooling. Each is a non-human identity that needs a credential or a network path, and each is a way in if that credential is shared or over-scoped.
| Caller | Endpoints it needs | Recommended pattern | Avoid |
|---|---|---|---|
| Kubernetes liveness and readiness probes | /actuator/health/liveness, /actuator/health/readiness (or /livez, /readyz with management.endpoint.health.probes.add-additional-paths=true) | Unauthenticated status only, details hidden; keep liveness free of external dependency checks as the documentation advises | Exposing full health details to make probes "work" |
| Prometheus or another scraper | prometheus or metrics | Management port reachable only from the monitoring network, or a scraper-only role with its own credential or mTLS client certificate | Scraping over the public ingress with a shared basic auth password |
| Spring Boot Admin or a similar console | Many read endpoints, sometimes loggers write | One credential per environment held in a secrets manager, rotated, scoped to read except where write is approved | One admin password in every service's application.yml |
| Spring Cloud Config refresh | refresh, busrefresh | Internal network only, service identity with a role limited to refresh | Enabling POST /actuator/env without valid-keys-regex |
| Engineers diagnosing incidents | threaddump, loggers, occasionally heapdump | Access through a privileged access path with just-in-time elevation and recording | Standing access from laptops to production management ports |
- Store the credentials properly: the management user's password or client certificate key belongs in a secrets manager or the platform's secret store, not in source control. See the Secrets Management Guide.
- Prefer network identity where it is strong: binding the management server to an internal address with
management.server.addressand a separatemanagement.server.port, plus a network policy that admits only the monitoring namespace, avoids distributing passwords at all. Inside a mesh, mTLS between scraper and service is stronger still. See the mTLS Guide. - Remember what Actuator reveals about other identities:
envandconfigpropslist every datasource user, cloud SDK setting and API client configured in the application. Even sanitised, that is an inventory of the service's non-human identities. See the Service Account Security Guide.
Logging and detection
Spring Boot's audit framework publishes authentication success, authentication failure and access denied events once Spring Security is present, but only if you supply an AuditEventRepository bean. The in-memory implementation is intended for development, so production services should forward events to their log pipeline. Combine those application events with edge and network logs.
| Signal | Source | Why it matters |
|---|---|---|
Any request to /actuator/* (or a custom base-path) arriving through the public ingress | Load balancer, WAF or ingress logs | If the management plane is separated correctly, this count should be zero |
Requests for heapdump, env, configprops, threaddump, logfile, gateway/routes | Edge logs and application access logs | These are the paths internet scanners probe for; repeated 401 or 404 responses still indicate targeting |
| Large responses from management paths | Proxy logs (bytes sent) | A successful heap dump download is hundreds of megabytes or more |
AUTHENTICATION_FAILURE and AUTHORIZATION_FAILURE audit events on Actuator paths | Actuator audit events | Credential guessing against the management role |
POST to loggers, env, refresh, restart, DELETE to sessions | Access logs, change management | Runtime changes that should match an approved change or incident |
Log level changes to DEBUG or TRACE in production | Application logs | Can cause secrets and personal data to be logged |
In ATT&CK terms, scanning and abuse of exposed Actuator endpoints sits under T1190 Exploit Public-Facing Application for the gateway code injection class, and under T1552.001 Credentials In Files and T1005 Data from Local System when the goal is harvesting configuration and memory. Treat a confirmed heap dump or unsanitised env download as a credential compromise: rotate every secret the process held, not just the obvious one. Our Cloud Credential Compromise Playbook covers the rotation sequence.
Metrics that show the controls hold
- Externally reachable Actuator endpoints: count from attack surface scans of every public hostname, target zero beyond
health. - Services with exposure set to
*: found by configuration scanning across repositories and running pods, target zero in production. - Services with a management-specific security chain: percentage of Spring Boot services where a test proves
/actuator/envreturns 401 or 403 without the management role. - Write-capable endpoints in production: number of services where
max-permittedis notread-only, each with a recorded owner and reason. - Shared management credentials: number of services using the same management secret, target one per environment or none where network identity is used.
Hardening baseline
A production baseline that matches the documented properties. Adjust endpoint lists to what your operators actually use.
| Setting | Baseline value | Reason |
|---|---|---|
management.endpoints.access.default | none | Opt-in: only named endpoints exist in the context |
management.endpoints.access.max-permitted | read-only | No write operation can be enabled by accident |
management.endpoint.health.access, .info.access, .prometheus.access | read-only | The minimum most platforms need |
management.endpoints.web.exposure.include | health,info,prometheus | Explicit list, never "*" |
management.endpoints.web.exposure.exclude | heapdump,env,configprops,threaddump,logfile | Belt and braces: exclude wins over include |
management.endpoints.jmx.exposure.exclude | "*" unless JMX is used and secured | JMX bypasses role-based value sanitisation |
management.server.port and .address | A separate port (for example 8081) bound to an internal interface | Public ingress never routes to the management listener |
management.endpoint.health.show-details and show-components | never, or when-authorized with roles | Health details reveal databases, brokers and their status |
management.endpoint.env.show-values (and configprops, quartz) | never | Keeps values sanitised even for authenticated users |
management.info.git.mode | simple or management.info.git.enabled=false | Avoids disclosing full repository metadata |
management.endpoints.web.cors.allowed-origins | Unset | CORS stays disabled for management endpoints |
Spring Cloud management.endpoint.env.post.enabled | Unset (false) | If ever enabled, set valid-keys-regex and restrict to an operator role |
Spring Cloud Gateway management.endpoint.gateway | Disabled unless needed, patched | CVE-2022-22947 required the Gateway endpoint to be enabled, exposed and unsecured |
Changing management.endpoints.web.base-path to an unusual value reduces scanner noise but is not a control. OWASP ASVS 5.0 requirement V13.4.5 asks that monitoring endpoints are not exposed unless explicitly intended, and V13.4.6 that backend version details are not exposed, which is a useful pass or fail test for this baseline.
Rolling out the baseline
- Inventory first: scan repositories for
spring-boot-starter-actuatorandmanagement.properties, and scan public hostnames for/actuatorand common alternate base paths. Record which services have a customSecurityFilterChain, because those no longer get Boot's default protection. - Close the network path: move management to a separate port bound to an internal address, update Kubernetes probes and scrape configs, and block
/actuator/**at the public ingress as a second layer. - Apply access settings in staging: set
access.default=noneandmax-permitted=read-only, enable only the endpoints your monitoring uses, and run the probe and scrape checks. Inaccessible endpoints are removed from the context, so failures show up immediately as 404s. - Add the management security chain: a dedicated
SecurityFilterChainwithsecurityMatcher(EndpointRequest.toAnyEndpoint())and a dedicated role, ordered before the application chain. Add an integration test that assertsenvandheapdumpreturn 401, 403 or 404 for an anonymous and an ordinary user. - Pilot and promote: roll to one service per team, watch probe failures and dashboards for a week, then make the baseline a shared starter or platform default so new services inherit it.
- Rollback: keep the previous property set in the deployment manifest history; reverting the management properties restores behaviour without code changes. Never roll back by setting exposure to
"*".
Decision guidance
- Separate port versus same port with security: a separate internal port is the stronger default for data centres and Kubernetes. The documentation notes that some platforms, such as Cloud Foundry, route only one port by default, where a same-port design with a strict management chain and edge blocking is the practical choice.
- Small teams: expose only
healthandprometheus, keep everything else inaccessible, and diagnose through logs and APM. - Large estates: publish a company starter that sets the baseline, provide a break-glass diagnostic path through privileged access tooling, and enforce the baseline with policy as code in the build.
Common misconfigurations
- Exposure set to
"*"to fix a monitoring integration: one line in a shared profile exposes every endpoint on every service that loads it. Exposure lists should be explicit and reviewed. - A custom security chain that forgets Actuator: the moment a team adds its own
SecurityFilterChainfor the API, Boot's default protection backs off. ApermitAll()on/**for a public API then also opens/actuator/**. - Trusting "internal" without checking the route: ingress rules, API gateways and service meshes often forward every path. Mass scanning finds these leaks quickly: the 230 Million AWS Cloud Environments Campaign harvested keys from exposed
.envfiles across more than 110,000 domains, and an unprotectedenvorheapdumpendpoint is the same class of exposure. - Turning on
show-values: alwaysduring debugging: it shows unsanitised values to everyone who can reach the endpoint, and it tends to survive into production config. - Leaving development profiles active: profiles that widen exposure, enable H2 consoles or debug logging are a frequent source of production exposure. Fail start-up if a development profile is active in production (ASVS V13.4.2).
- Unpatched Spring Cloud components behind Actuator: CVE-2022-22947 in Spring Cloud Gateway, listed in the CISA Known Exploited Vulnerabilities catalogue since May 2022, allowed code injection through the Gateway Actuator endpoint when it was enabled, exposed and unsecured. Exposure turned a management feature into remote code execution.
Framework mapping
| Framework | Reference | How it applies to Actuator |
|---|---|---|
| NIST SP 800-53 Rev. 5 | CM-7 Least Functionality | Opt-in access, explicit exposure lists, unused endpoints inaccessible |
| NIST SP 800-53 Rev. 5 | AC-6 Least Privilege | Dedicated management role, read-only cap, separate write role |
| NIST SP 800-53 Rev. 5 | SC-7 Boundary Protection | Separate management port and internal address, ingress blocking |
| NIST SP 800-53 Rev. 5 | AU-2 Event Logging | Actuator audit events and management path access logs |
| NIST CSF 2.0 | PR.PS-01 | Configuration management practices applied to management properties |
| OWASP ASVS 5.0 | V13.4.5, V13.4.2, V13.4.6, V8.2.1 | Monitoring endpoints not exposed, debug modes off, no version disclosure, function-level access control |
| OWASP API Security Top 10 2023 | API8:2023 Security Misconfiguration | Exposed diagnostic endpoints and verbose configuration |
| MITRE ATT&CK v20 | T1190, T1552.001, T1005 | Exploitation of exposed endpoints and harvesting of configuration and memory contents |
See the OWASP API Top 10 API8 Security Misconfiguration Guide for the wider misconfiguration class.
Practitioner checklist
- Inventory every service that depends on
spring-boot-starter-actuatorand scan all public hostnames for management paths. - Set
management.endpoints.access.default=noneandmax-permitted=read-onlyin production, then opt in endpoints by name. - Replace any
exposure.include="*"with an explicit list and excludeheapdump,env,configprops,threaddumpandlogfile. - Move management to a separate internal port and address, and block
/actuator/**at the public edge. - Add a dedicated
SecurityFilterChainforEndpointRequest.toAnyEndpoint()with its own role, plus an automated test proving anonymous access is refused. - Keep
show-valuesatneverandhealth.show-detailsatneverorwhen-authorizedwith roles. - Give scrapers, probes and admin consoles their own scoped identities, stored in a secrets manager, or rely on network identity and mTLS.
- Disable or secure Spring Cloud Gateway and Spring Cloud Commons write endpoints and keep those components patched against KEV-listed CVEs.
- Forward Actuator audit events to the SIEM and alert on management path hits at the edge and on runtime log level changes.
- Treat any confirmed heap dump or unsanitised env download as a full credential compromise and rotate every secret the process held.
Standards and references
- Spring: Spring Boot Reference, Actuator Endpoints
- Spring: Spring Boot Reference, Monitoring and Management Over HTTP
- Spring: Spring Boot Reference, Auditing
- Spring: Spring Cloud Commons, Spring Cloud Context Application Context Services
- Spring: CVE-2022-22947 Code Injection in Spring Cloud Gateway
- OWASP: Application Security Verification Standard 5.0
- CISA: Known Exploited Vulnerabilities Catalog
- NIST: SP 800-53 Rev. 5
Related NHI Mgmt Group resources: Java and Spring Security Guide · Spring Security Configuration Guide · Secrets Management Guide · Kubernetes Security Guide · Attack Surface Management Guide