lowSeverity: lowRisk ratingHow usable this gap is to an attacker. Severity sets the posture penalty: critical −40, high −20, medium −10, low −4, info −1. Higher severity means fix it sooner.App server / gateway configWhere it livesImplementationThis fix is applied in: App server / gateway config. That's the surface you'll edit, DNS, response headers, or a static file.~10 minTime to fixEffortRoughly 10 minutes of hands-on work, propagation aside. Most of these are copy-paste.+4 posture+4 postureScore impactPoints this fix recovers in the ApeCyber posture score (0–100). Posture = 100 minus the severity penalty of every open finding; clearing this finding adds these points back.

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 /metrics to 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.