CVE-2026-54246 Overview
CVE-2026-54246 is a missing authentication vulnerability [CWE-306] in Zalando Skipper, an HTTP router and reverse proxy for service composition. The routesrv component serves cluster-wide control-plane data through /routes, /routes/{zone}, /swarm/redis/shards, and /swarm/valkey/shards without application-layer authentication. Any pod that can reach routesrv on the Kubernetes cluster network can retrieve Ingress and RouteGroup backend URLs, filter-chain configuration, OAuth or OIDC path details, and Redis or Valkey shard addresses across namespaces. The flaw is fixed in Skipper version 0.27.13.
Critical Impact
A compromised or attacker-controlled pod on the cluster network can bypass namespace-scoped RBAC and read routing, filter, and shard-address data from every namespace served by routesrv.
Affected Products
- Zalando Skipper versions prior to 0.27.13
- Skipper routesrv component in Kubernetes deployments
- Clusters running Skipper as the ingress controller with routesrv reachable from workload pods
Discovery Timeline
- 2026-09-14 - CVE-2026-54246 published to NVD
- 2026-09-16 - Last updated in NVD database
Technical Details for CVE-2026-54246
Vulnerability Analysis
Skipper's routesrv process distributes route configuration to Skipper proxy instances by serving control-plane data over HTTP. The handlers registered in routesrv/routesrv.go, along with eskipBytes.ServeHTTP in routesrv/eskipbytes.go, RedisHandler.ServeHTTP in routesrv/redishandler.go, and ValkeyHandler.ServeHTTP in routesrv/valkeyhandler.go, only enforce HTTP method restrictions. None of these handlers authenticate the caller.
When a workload pod reaches routesrv over the cluster network, it can enumerate cross-namespace routing details that Kubernetes RBAC would normally hide. Exposed data includes backend service URLs behind Ingress and RouteGroup resources, filter chains that document OAuth or OIDC paths, and Redis or Valkey shard addresses used for rate limiting and swarm coordination. This information significantly aids lateral movement and further reconnaissance inside the cluster.
Root Cause
The root cause is missing authentication for a critical function [CWE-306]. The routesrv HTTP handlers were designed to serve peer Skipper proxies and did not implement caller verification, treating network reachability as sufficient authorization. Kubernetes NetworkPolicy can reduce reachability, but it does not correct the missing-authentication condition itself.
Attack Vector
Exploitation requires network access to the routesrv service and low privileges within the cluster. An attacker with a foothold in any pod that can route to routesrv sends unauthenticated GET requests to the exposed endpoints and receives full route and shard metadata. The recorded impact is confidentiality exposure; the endpoints do not enable direct integrity or availability loss.
// Security patch: config/config.go — introduces route-server-filters
// so operators can attach an arbitrary filter chain (including auth)
// to routesrv's call path.
KubernetesForceService bool `yaml:"kubernetes-force-service"`
KubernetesStatusFromService string `yaml:"kubernetes-status-from-service"`
// RouteServer
RouteServerFilters *defaultFiltersFlags `yaml:"route-server-filters"`
// Default filters
DefaultFiltersDir string `yaml:"default-filters-dir"`
Source: Skipper commit fb3d5f9
// Security patch: routesrv/filter.go — new filterContext lets filters
// authenticate and short-circuit requests to routesrv endpoints.
package routesrv
import (
"io"
"net/http"
ot "github.com/opentracing/opentracing-go"
log "github.com/sirupsen/logrus"
"github.com/zalando/skipper/filters"
"github.com/zalando/skipper/metrics"
)
type filterContext struct {
w http.ResponseWriter
req *http.Request
rsp *http.Response
metrics metrics.Metrics
served bool
stateBag map[string]interface{}
}
func (fc *filterContext) ResponseWriter() http.ResponseWriter { return fc.w }
func (fc *filterContext) Request() *http.Request { return fc.req }
func (fc *filterContext) Response() *http.Response { return fc.rsp }
func (fc *filterContext) OriginalRequest() *http.Request { return fc.req }
Source: Skipper pull request #4056
Detection Methods for CVE-2026-54246
Indicators of Compromise
- Unexpected HTTP GET traffic to routesrv on paths /routes, /routes/{zone}, /swarm/redis/shards, or /swarm/valkey/shards originating from workload pods rather than Skipper proxy pods.
- Access log entries on routesrv showing source IPs that do not correspond to authorized Skipper proxy replicas.
- Outbound egress or lateral connections to backend service URLs shortly after routesrv enumeration.
Detection Strategies
- Enable and review routesrv HTTP access logging, correlating source pod identity against a known allow-list of Skipper proxy replicas.
- Deploy Kubernetes audit and network flow analytics to flag pods that establish new connections to the routesrv service or port.
- Alert on high-volume or repeated GET requests to the four exposed endpoints from a single client within short time windows.
Monitoring Recommendations
- Instrument Kubernetes NetworkPolicy denial counters and log dropped attempts to reach routesrv.
- Ingest ingress-controller and Kubernetes API audit logs into a centralized analytics platform for cross-namespace correlation.
- Track Skipper version inventory across clusters to identify hosts still running versions prior to 0.27.13.
How to Mitigate CVE-2026-54246
Immediate Actions Required
- Upgrade all Skipper deployments to version 0.27.13 or later.
- Apply a Kubernetes NetworkPolicy that limits routesrv ingress to Skipper proxy pods only.
- Configure the new route-server-filters option to attach an authentication filter chain to routesrv endpoints.
- Audit recent routesrv access logs for unauthorized clients and rotate any credentials or secrets referenced by exposed filter chains.
Patch Information
The fix is delivered in Skipper release v0.27.13 via pull request #4056 and commit fb3d5f9. The patch adds a RouteServerFilters configuration flag and a minimal filterContext that lets operators run arbitrary Skipper filters, including authentication filters, in front of the routesrv handlers. See the GHSA-5587-2x54-jj6h advisory for full details.
Workarounds
- Restrict routesrv reachability with a strict NetworkPolicy that allows only Skipper proxy pods as ingress sources.
- Bind routesrv to a dedicated internal service or namespace isolated from general workload pods.
- Terminate routesrv traffic behind a mutually authenticated proxy (mTLS) until upgrade is possible.
# Example NetworkPolicy restricting access to routesrv
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
name: routesrv-restrict
namespace: skipper
spec:
podSelector:
matchLabels:
app: skipper-routesrv
policyTypes:
- Ingress
ingress:
- from:
- podSelector:
matchLabels:
app: skipper-ingress
ports:
- protocol: TCP
port: 9911
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.