/actuator/health Web access log Triage: medium

GET /actuator Requests in Your Logs: Spring Boot Actuator Probing

Published

An automated scan for Spring Boot Actuator management endpoints, which expose configuration, environment properties and full JVM heap dumps whenever they are reachable without authentication.

What it looks like

203.0.113.7 - - [18/Oct/2026:03:51:11 +0000] "GET /actuator HTTP/1.1" 404 162 "-" "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36"
198.51.100.42 - - [18/Oct/2026:03:51:12 +0000] "GET /actuator/env HTTP/1.1" 404 162 "-" "python-requests/2.31.0"
192.0.2.88 - - [18/Oct/2026:04:02:44 +0000] "GET /actuator/heapdump HTTP/1.1" 404 162 "-" "Go-http-client/2.0"

On our own server, the 30 days to 18 October 2026

434

requests · about 14 a day

47

source addresses

Most requested variantsRequests
/actuator/health37
/actuator/env37
/actuator18
/actuator/configprops18
/actuator/heapdump16
/actuator/logfile15
/actuator/mappings15
/actuator/threaddump14

LogTriage's production API server (Hetzner, Germany): port 22 open to the internet, key-only since 6 October 2026 (password and keyboard-interactive authentication off); nginx in front of the API on ports 80 and 443. Paths as requested, query strings dropped and identifiers redacted; counted weekly from the nginx access log. More in the monthly attack report.

What the request is

Spring Boot Actuator is the monitoring and management module for Spring Boot applications. When it is on the classpath it adds a tree of HTTP endpoints under a base path, /actuator by default, and GET /actuator returns a discovery document listing the endpoints that are currently exposed. That single response tells a scanner both that the target is a Spring Boot application and which of the interesting paths to try next.

The endpoints below it are operational tooling, and that is exactly what makes them worth probing:

  • /actuator/env and /actuator/configprops — environment properties and bound configuration-properties beans: datasource URLs, hostnames, user names, cloud and mail settings. Spring sanitises values whose property names look like secrets, and newer versions mask property values unless show-values is configured, so what is readable depends on your version and settings — but internal hostnames and the shape of the deployment leak regardless.
  • /actuator/heapdump — a full JVM heap dump as a downloadable file. Nothing in it is sanitised. Credentials, tokens and session data that were in memory at that moment are in the file.
  • /actuator/logfile — the application log, when a log file is configured.
  • /actuator/threaddump — thread stacks, revealing frameworks, library versions and internal class names.
  • /actuator/mappings — every request mapping the application serves, including routes that are not linked anywhere.

Older Spring Boot 1.x applications served the same endpoints directly at the root (/env, /health, /beans), so scanners that ask for /actuator/env usually ask for /env in the same pass.

Who sends it

This is undirected, internet-wide scanning: mass scanners sweeping address ranges, botnets that feed recovered credentials straight into further abuse, and research crawlers cataloguing exposed management interfaces. A request to /actuator does not mean your organisation was selected.

User agents are no help in identifying them — some announce an HTTP library such as python-requests or Go-http-client, many copy a current Chrome string. The shape is the tell: a short burst from one address, no Referer, no requests for static assets, and a path list that walks on to other well-known management and secret files once /actuator answers 404.

Is your server exposed?

Check what you already answered, then ask your own host:

# Every /actuator path in the log, with the status code it received
awk '$7 ~ /^\/actuator/ {print $9, $7}' /var/log/nginx/access.log \
  | sort | uniq -c | sort -rn | head -20

# Anything that was NOT a 404/403 — this is the list that matters
awk '$7 ~ /^\/actuator/ && $9 !~ /^(404|403)$/' /var/log/nginx/access.log

# Ask your own server, through nginx
for p in /actuator /actuator/env /actuator/configprops /actuator/heapdump /actuator/logfile; do
  printf '%s -> ' "$p"
  curl -s -o /dev/null -w '%{http_code}\n' "http://127.0.0.1$p"
done

# And directly on the application port, which may be published separately
ss -ltnp

Run the loop against every vhost name you serve, not just the default one, and against the application port itself — an edge rule on the main site with the app container also publishing 8080 is the usual way these endpoints stay reachable. Rotated logs deserve the same awk pass, in case an exposure was fixed after it was used.

How to block it

Deny the whole tree at the proxy, and keep any endpoint you genuinely need as a narrower, source-restricted exception:

# Health check for the internal monitoring network only
location = /actuator/health {
    allow 10.0.0.0/8;
    deny all;
    proxy_pass http://127.0.0.1:8080;
}

# Everything else under the actuator tree: not found, not logged
location ^~ /actuator {
    access_log off;
    return 404;
}

The exact-match location is evaluated ahead of the prefix location, so the health probe keeps working while /actuator/env and /actuator/heapdump are answered 404. Returning 404 rather than 403 also tells the scanner nothing about what exists.

Fix it in the application too, because the proxy is only one path to the port. Keep management.endpoints.web.exposure.include to the endpoints operations actually uses — a wildcard * there is the usual reason a whole actuator tree is reachable — move management to its own port with management.server.port and bind that port to an internal address, and require authentication on the management endpoints with Spring Security. If a heap dump, environment listing or log file was ever served with a 200, the block is not the end of the work: treat the contents as disclosed and rotate what they could have held.

Probes that arrive with it

Detect it

MITRE ATT&CK: T1595.003T1592.002T1552.001

Frequently Asked Questions

Every one of these gets a 404 on our edge. Is there anything to do?
Not as an incident. A 404 means nothing was disclosed and the scanning will not stop. The useful work is preventive: confirm the application port itself is not reachable from the internet separately from nginx, confirm the actuator block exists on every vhost rather than only the main one, and alert on non-404 responses to /actuator paths instead of on the requests.
/actuator/health returns 200 on our site — is that a disclosure?
Usually not on its own. In current Spring Boot versions the health endpoint defaults to showing details only when show-details is configured, so an anonymous caller normally sees a status value and nothing else. Check what your deployment actually returns, because a configured show-details can list database, disk and message-broker components and their state.
A scanner got a 200 from /actuator/heapdump. What is the clean-up?
Treat it as a credential disclosure. A heap dump is a snapshot of process memory, so anything the JVM held — datasource passwords, API keys, session identifiers, tokens in flight — may be in the file the scanner downloaded. Rotate those secrets, invalidate sessions, then search the access log for other non-404 /actuator responses from the same addresses.
Is blocking /actuator at nginx enough?
It is the right first move but not the whole fix. If the application port is also published, or another ingress, load balancer or service mesh route reaches the app, the endpoints stay reachable around nginx. Pair the edge rule with limiting exposed endpoints in the application and binding management to a separate, internal-only port.

See what else is probing your server

Drop an nginx or Apache access log into the free browser analyzer: secret-file sweeps, exploit probes, scanners and credential stuffing are grouped by source with the evidence lines, and every known probe links back here. Nothing is uploaded.