Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐹
🐹 Go
Not in CISA KEV
MEDIUM severity

CVE-2026-54246

MEDIUM

CVE-2026-54246 is a medium-severity (CVSS 5.7) vulnerability in github.com/zalando/skipper. O3 Security confirms whether CVE-2026-54246 is actually reachable in your code before you act, and blocks exploitation at runtime until you patch.

Skipper's routesrv-no-auth component: All routesrv API Endpoints Lack Authentication

Also known asGO-2026-6018
Published
Jul 17, 2026
Updated
Jul 22, 2026
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Jul 22, 2026 · OSV.dev, FIRST.org (EPSS)

Real-World Exposure

1 pkg affected
🐹github.com/zalando/skipper

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Go packages — download data is not available via public APIs for these ecosystems.

Description

Description

The routesrv component exposes the full cluster route topology (Ingress/RouteGroup configurations, backend URLs, filter chains, OAuth/OIDC callback paths) and cache-cluster topology (Redis/Valkey shard addresses) over plain HTTP with zero authentication. Any pod in the Kubernetes cluster can reach routesrv via its predictable DNS name and retrieve sensitive cluster-wide routing and cache infrastructure data.

Vulnerable Code

routesrv/routesrv.go:87-99,114-137 — all handler registrations on the main mux:

mux.Handle("/routes", b)          // eskipBytes.ServeHTTP — all route data
mux.Handle("/routes/{zone}", b)   // zone-scoped route data
mux.Handle("/swarm/redis/shards", rh)   // Redis cluster addresses
mux.Handle("/swarm/valkey/shards", vh)  // Valkey cluster addresses

routesrv/eskipbytes.go:134-196eskipBytes.ServeHTTP:

func (e *eskipBytes) ServeHTTP(rw http.ResponseWriter, r *http.Request) {
    // ... only checks GET/HEAD method, NO auth check
    if r.Method != "GET" && r.Method != "HEAD" {
        w.WriteHeader(http.StatusMethodNotAllowed)
        return
    }
    // ... serves all route data immediately
}

routesrv/redishandler.go:28-41RedisHandler.ServeHTTP:

func (rh *RedisHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if r.Method != "GET" {
        w.WriteHeader(http.StatusMethodNotAllowed)
        return
    }
    // ... serves Redis cluster addresses immediately, NO auth check
}

routesrv/valkeyhandler.go:28-41ValkeyHandler.ServeHTTP:

func (vh *ValkeyHandler) ServeHTTP(w http.ResponseWriter, r *http.Request) {
    if r.Method != "GET" {
        w.WriteHeader(http.StatusMethodNotAllowed)
        return
    }
    // ... serves Valkey cluster addresses immediately, NO auth check
}

Attack Path

  1. Initial Compromise: Attacker compromises any pod in the Kubernetes cluster (via application CVE, supply-chain attack, malicious container image, etc.)
  2. Discovery: Attacker discovers routesrv via predictable Kubernetes DNS name: skipper-ingress-routesrv.kube-system.svc.cluster.local:9090 (documented at docs/tutorials/operations.md:108, docs/tutorials/ratelimit.md:137,197)
  3. Data Extraction without Auth:
    • GET http://<routesrv>:9090/routes → All Ingress/RouteGroup configurations across ALL namespaces
    • GET http://<routesrv>:9090/swarm/redis/shards → Redis cache cluster node addresses
    • GET http://<routesrv>:9090/swarm/valkey/shards → Valkey cache cluster node addresses
  4. Subsequent Attacks: With cache cluster topology, attacker can perform direct cache-level attacks (ratelimit data manipulation, session data exfiltration)

Permission Boundary Analysis

The routesrv uses a ServiceAccount with cluster-wide RBAC to list Ingress (networking.k8s.io), RouteGroup (zalando.org), Endpoints, and Services across all namespaces (see clusterclient.go:648-653 fetchClusterState). The kube-apiserver requires proper ServiceAccount token + RBAC authorization for the Kubernetes API itself, but routesrv exposes the aggregated data over HTTP with zero authentication.

A compromised pod with limited RBAC (restricted to its own namespace) can bypass Kubernetes RBAC entirely by reading routesrv. This crosses the boundary from "namespace-scoped Kubernetes workload with restricted RBAC" to "full cluster route topology across all namespaces".

No NetworkPolicy manifests exist in the deploy/ directory. The default Kubernetes flat network model allows any pod to reach any service, further widening the attack surface.

Exposed Data

EndpointData ExposedImpact
GET /routesAll ingress/routegroup backends: internal service URLs, filter chains (auth, rate limiting, OAuth, JWT, OPA policies), load balancer group membershipCluster-wide reconnaissance, targeted backend attacks
GET /routes/{zone}Zone-scoped subset of above route dataSame, scoped
GET /swarm/redis/shardsRedis cluster internal IP:port pairsDirect cache-level attacks, ratelimit data manipulation
GET /swarm/valkey/shardsValkey cluster internal IP:port pairsSame

Additionally, the data-plane client (eskipfile/remote.go:190-219) also performs plain HTTP GET with no credentials — only an ETag header is sent — confirming that no auth capability exists in the architecture at all.

Mitigation

  1. Add authentication to all routesrv HTTP endpoints (basic auth, bearer token, mTLS, or shared secret) via flag -route-server-filters=""
  2. Deploy Kubernetes NetworkPolicies restricting ingress to routesrv to only the data-plane skipper pod selectors
  3. Consider using mutual TLS authentication between data-plane and control-plane components

NetworkPolicy does not remove the missing-auth condition

Restrictive NetworkPolicies are a valid mitigation, but they are not an application-layer authentication mechanism. The security-relevant defect remains that routesrv serves control-plane-derived data to unauthenticated callers whenever network reachability exists.

Impact framing

This report does not rely on claiming direct integrity or availability impact. The verified issue is a confidentiality-focused control-plane exposure: route definitions, backend topology, filter-chain details, and Redis/Valkey shard addresses become readable to any reachable in-cluster client.

Resources

  • routesrv/routesrv.go:87-99 — handler registration (zero auth)
  • routesrv/eskipbytes.go:134-196 — route data handler (no auth)
  • routesrv/redishandler.go:28-41 — Redis shard handler (no auth)
  • routesrv/valkeyhandler.go:28-41 — Valkey shard handler (no auth)
  • dataclients/kubernetes/clusterclient.go:648-653fetchClusterState() — shows cluster-wide RBAC
  • eskipfile/remote.go:190-219 — data-plane client also has no auth capability
  • docs/tutorials/operations.md:108, docs/tutorials/ratelimit.md:137,197 — documented routesrv DNS name

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐹Gogithub.com/zalando/skipperall versions0.27.13

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for github.com/zalando/skipper. O3's reachability analysis confirms whether the vulnerable code path is actually invoked in your application, so you act on real exposure instead of every transitive match.

  2. Fix

    Update github.com/zalando/skipper to 0.27.13 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-54246 is resolved across your whole dependency graph.

  3. Workarounds

    If you can't upgrade right away: gate or disable the affected feature, validate untrusted input at the boundary, and avoid passing attacker-controlled data into the vulnerable path. O3's runtime protection blocks exploitation in production as an interim safeguard until the upgrade lands.

  4. How O3 protects you

    O3 pinpoints whether CVE-2026-54246 is reachable in your code and exactly where to fix it, then blocks exploitation in production at runtime until the patched version is deployed.

Tailored to CVE-2026-54246. Runtime protection reduces exposure until a permanent patch is applied and verified — it complements patching, it doesn't replace it.

Frequently Asked Questions

## Description The `routesrv` component exposes the full cluster route topology (Ingress/RouteGroup configurations, backend URLs, filter chains, OAuth/OIDC callback paths) and cache-cluster topology (Redis/Valkey shard addresses) over plain HTTP with **zero authentication**. Any pod in the Kubernetes cluster can reach routesrv via its predictable DNS name and retrieve sensitive cluster-wide routing and cache infrastructure data. ## Vulnerable Code **routesrv/routesrv.go:87-99,114-137** — all handler registrations on the main mux: ```go mux.Handle("/routes", b) // eskipBytes.ServeHT
O3 Security · Impact-Aware SCA

Is CVE-2026-54246 in your dependencies?

O3 detects CVE-2026-54246 across Go dependencies and uses function-level reachability to confirm whether the vulnerable code path is actually reachable — not just present. No false positives.

CVE-2026-54246: skipper (Medium 5.7) | O3 Security