fix(security): SSRF guard gaps + DNS port restriction + metrics auth #112

Merged
lerko merged 1 commits from fix/security-hardening into main 2026-06-11 23:04:06 +00:00
Owner

Summary

Three security hardening fixes from the review-findings backlog.

  1. SSRF guard now blocks 0.0.0.0/8 + CGNAT — on Linux, http://0.0.0.0:port/ routes to localhost and passed the old filter. Added 0.0.0.0/8, 100.64.0.0/10 (CGNAT), plus ip.IsUnspecified()/ip.IsMulticast()/ip.IsLoopback() for defense in depth.

  2. DNS monitor no longer bypasses SSRF guardDNSServer was user-controlled with no validation. Now resolves the server address and validates against isPrivateIP. Port restricted to 53 to prevent internal port probing. Both checks respect UPTOP_ALLOW_PRIVATE_TARGETS — when set, private DNS servers and non-53 ports are allowed.

  3. /metrics default-deny without cluster secret!MetricsPublic && ClusterKey != "" meant no secret = no auth = metrics exposed. Now uses requireAuth() which returns false when no key is configured, so /metrics requires either MetricsPublic=true or a valid cluster secret.

Test plan

  • go test -count=1 ./... — all pass
  • golangci-lint — 0 issues
  • DNS SSRF guard respects allowPrivate flag (private DNS servers work with UPTOP_ALLOW_PRIVATE_TARGETS=true)
## Summary Three security hardening fixes from the review-findings backlog. 1. **SSRF guard now blocks 0.0.0.0/8 + CGNAT** — on Linux, `http://0.0.0.0:port/` routes to localhost and passed the old filter. Added `0.0.0.0/8`, `100.64.0.0/10` (CGNAT), plus `ip.IsUnspecified()`/`ip.IsMulticast()`/`ip.IsLoopback()` for defense in depth. 2. **DNS monitor no longer bypasses SSRF guard** — `DNSServer` was user-controlled with no validation. Now resolves the server address and validates against `isPrivateIP`. Port restricted to 53 to prevent internal port probing. Both checks respect `UPTOP_ALLOW_PRIVATE_TARGETS` — when set, private DNS servers and non-53 ports are allowed. 3. **`/metrics` default-deny without cluster secret** — `!MetricsPublic && ClusterKey != ""` meant no secret = no auth = metrics exposed. Now uses `requireAuth()` which returns false when no key is configured, so `/metrics` requires either `MetricsPublic=true` or a valid cluster secret. ## Test plan - [x] `go test -count=1 ./...` — all pass - [x] `golangci-lint` — 0 issues - [x] DNS SSRF guard respects `allowPrivate` flag (private DNS servers work with `UPTOP_ALLOW_PRIVATE_TARGETS=true`)
lerko added 1 commit 2026-06-11 22:59:13 +00:00
fix(security): SSRF guard gaps + DNS port restriction + metrics auth
CI / test (pull_request) Successful in 1m54s
CI / lint (pull_request) Successful in 1m27s
CI / vulncheck (pull_request) Successful in 1m1s
f7da69f25f
1. SSRF guard now blocks 0.0.0.0/8 (routes to localhost on Linux)
   and 100.64.0.0/10 (CGNAT). Also rejects unspecified, multicast,
   and loopback IPs via net.IP methods for defense in depth.

2. DNS monitor type no longer bypasses SSRF guard. The DNSServer
   address is resolved and validated against isPrivateIP before use.
   Port restricted to 53 — prevents arbitrary internal port probing
   via crafted DNSServer values.

3. /metrics now default-deny when MetricsPublic is false, regardless
   of whether UPTOP_CLUSTER_SECRET is set. Previously, no secret =
   no auth check = metrics exposed to everyone.
lerko merged commit f7da69f25f into main 2026-06-11 23:04:06 +00:00
lerko deleted branch fix/security-hardening 2026-06-11 23:04:06 +00:00
Sign in to join this conversation.
No Reviewers
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: lerkolabs/uptop#112