Exposed /metrics: bind Prometheus metrics to your internal network
Binding /metrics to an internal interface stops the public reading your routes, hostnames, and traffic.
The threat
The scanner requested /metrics and got back Prometheus exposition format (lines like # HELP, # TYPE, and counters such as http_requests_total{...}). That endpoint exists so your monitoring can scrape it. It was not meant for the public, and there is no reason for it to answer requests from the open internet.
On its own no single metric is a disaster, which is why this is low severity, but together they make a tidy reconnaissance packet: internal hostnames and instance labels, every route and path your app serves (they show up as labels), build and version info, and request counts and latencies that reveal which endpoints exist and which get the most traffic. It saves an attacker the work of mapping you by hand.
The exact fix
Serve metrics on something only your monitoring can reach, not the public interface.
Bind the metrics listener to an internal interface or a separate internal port. Most exporters and frameworks let you set the address:
# Spring Boot actuator: management on its own internal port
management.server.port=9091
management.server.address=127.0.0.1
Expose the endpoint only on that internal port, and do not publish it to the internet.
If metrics must share the app’s public port, block /metrics at the edge and allow only your monitoring’s source addresses:
location = /metrics {
allow 10.0.0.0/8; # your monitoring network
deny all;
}
Handle /actuator/prometheus (Spring Boot’s path) the same way.
Do not just rename the path. Moving
/metricsto a secret URL is not protection, since scanners guess common paths. Bind it internally or allowlist the scraper by address; obscurity alone is not the fix.
Verify it
curl -s -o /dev/null -w '%{http_code}\n' https://yourdomain.com/metrics
From outside your network you want 403 or 404, not a 200 whose body contains # HELP and # TYPE lines.
Proof
The ApeCyber scanner confirms this with a single GET returning Prometheus format, from the outside, touching nothing. apecyber.com is a static Netlify site with no public /metrics endpoint to scrape, and it grades A / 100. Even at low severity, binding it internally is a free −4 off the posture score.