Zalando Skipper CVE-2026-54247
MEDIUMSeverity by source
AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:L
PR:L reflects the valid client certificate requirement; A:L chosen because kubelet auto-restarts process, preventing sustained unavailability.
Primary rating from GitHub Advisory.
CVSS VectorGitHub Advisory
Lifecycle Timeline
2DescriptionGitHub Advisory
Summary
The Kubernetes admission webhook handler reads the entire request body using io.ReadAll(r.Body) without any size limit. Any client that can reach the webhook port within the cluster can send a multi-GB payload, causing the skipper process to exhaust memory and be OOM-killed. This disrupts all Kubernetes admission control, potentially blocking all pod creation and updates.
Vulnerable Code
// dataclients/kubernetes/admission/admission.go:76
body, err := io.ReadAll(r.Body) // <-- NO SIZE LIMIT
if err != nil {
log.Errorf("Failed to read request: %v", err)
w.WriteHeader(http.StatusInternalServerError)
invalidRequests.WithLabelValues(admitterName).Inc()
return
}
var review admissionReview
err = json.Unmarshal(body, &review)For comparison, the OPA filter has a body size limit:
// filters/openpolicyagent/openpolicyagent.go:68-70
const DefaultMaxRequestBodySize = 1 << 20 // 1MB
// OPA uses a bufferedBodyReader with size limitsAttack Path
- Attacker identifies the admission webhook endpoint (default:
:9443/admissionor configured path) - Attacker sends:
POST /admission HTTP/1.1, Content-Type: application/jsonwith a multi-GB request body io.ReadAll(r.Body)allocates unbounded memory for the entire body- Skipper process is OOM-killed by the Kubernetes kubelet
Permission Boundary Analysis
- Attacker: Any client with network access to the admission webhook port within the Kubernetes cluster
- Boundary crossed: Memory safety - unbounded allocation from attacker-controlled input
- Preconditions: Admission webhook endpoint must be network-reachable (default Kubernetes deployment exposes it within cluster network)
- Comparison: OPA filter has
DefaultMaxRequestBodySize(1MB) and semaphore-based memory limit; admission handler has neither
Evidence
| File | Lines | Description |
|---|---|---|
dataclients/kubernetes/admission/admission.go | 76 | io.ReadAll(r.Body) without size limit |
filters/openpolicyagent/openpolicyagent.go | 68-70 | OPA filter has DefaultMaxRequestBodySize = 1MB |
filters/openpolicyagent/openpolicyagent.go | 1333-1336 | OPA uses bufferedBodyReader with size limits |
Tests
dataclients/kubernetes/admission/admission_test.goexists but does not test body size limits
Impact
The admission webhook handler reads the entire request body using io.ReadAll(r.Body) without a size limit. An attacker with in-cluster network access and a valid Kubernetes client certificate can send a multi-GB payload to the webhook endpoint, causing the skipper process to exhaust memory and be OOM-killed. This disrupts admission control for Ingress and RouteGroup resources until the process is automatically restarted by the kubelet.
Scope of impact: Ingress and RouteGroup admission only - not pod creation or other admission controllers.
Recovery: Kubernetes automatically restarts the OOM-killed process, limiting downtime.
Prerequisites: (1) In-cluster network access to the webhook port, (2) valid Kubernetes client certificate.
Mitigation
- Add
http.MaxBytesReaderor equivalent body size limit beforeio.ReadAll - Follow the OPA filter pattern: define
DefaultMaxRequestBodySizeand use a buffered reader with size limits - Add a configurable
--admission-max-body-sizeflag
AnalysisAI
Memory exhaustion denial-of-service in Zalando Skipper's Kubernetes admission webhook handler allows any authenticated in-cluster client to OOM-kill the skipper process by submitting an oversized HTTP request body. The Go handler at dataclients/kubernetes/admission/admission.go:76 calls io.ReadAll(r.Body) with no preceding size guard, enabling unbounded heap allocation from attacker-controlled input (CWE-770). No public exploit has been identified at time of analysis; recovery is automatic via kubelet pod restart, but the disruption window blocks Ingress and RouteGroup admission operations for the cluster.
Technical ContextAI
Skipper (pkg:go/github.com/zalando/skipper) is a Golang HTTP router and reverse proxy used as a Kubernetes ingress controller by Zalando and adopters of their open-source stack. Its admission webhook - registered by default on port 9443 at the /admission path - handles AdmissionReview objects for Ingress and RouteGroup resources. The root cause is CWE-770 (Allocation of Resources Without Limits or Throttling): io.ReadAll(r.Body) at admission.go:76 is called with no http.MaxBytesReader wrapper or equivalent buffered-reader guard. This design gap is internally inconsistent: the OPA filter component in the same codebase (filters/openpolicyagent/openpolicyagent.go:68-70) defines DefaultMaxRequestBodySize = 1MB and wraps reads in a bufferedBodyReader with semaphore-based limits. The admission handler has neither. The affected package identifier is pkg:go/github.com_zalando_skipper for all versions prior to 0.26.22.
RemediationAI
Upgrade Skipper to v0.26.22 or later, which introduces a bounded body read in the admission webhook handler (fix PR #4053), per the release notes at https://github.com/zalando/skipper/releases/tag/v0.26.22. The fix follows the existing OPA filter pattern by applying http.MaxBytesReader or an equivalent buffered reader with a defined size cap before io.ReadAll. If an immediate upgrade is not feasible, restrict network access to the webhook port (default TCP 9443) via Kubernetes NetworkPolicy to permit only the Kubernetes API server as a source - this prevents arbitrary in-cluster clients from reaching the endpoint directly. Note that NetworkPolicy enforcement depends on your CNI plugin (e.g., Calico, Cilium, Weave); verify enforcement is active before relying on this control, as misconfigured or absent CNI enforcement would leave the port fully reachable. Imposing explicit memory resource limits on the skipper pod provides partial resilience by capping how much memory the process can consume before the OOM kill, but does not prevent the attack from triggering repeated disruption cycles. Do not rely on memory limits alone as the primary mitigation.
More in Kubernetes
View allA critical vulnerability in Kubernetes ingress-nginx controller allows unauthenticated attackers with pod network access
Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio
Kubernetes ingress-nginx contains a configuration injection vulnerability via the mirror-target and mirror-host Ingress
A security issue was discovered in ingress-nginx https://github.com/kubernetes/ingress-nginx where the `auth-url` Ingres
A security issue was discovered in ingress-nginx https://github.com/kubernetes/ingress-nginx where the `auth-tls-match-c
Kubernetes API server in all versions allow an attacker who is able to create a ClusterIP service and set the spec.exter
A security issue was discovered in Kubernetes where a user that can create pods on Windows nodes may be able to escalate
Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes. Rated critical severity (CVSS 9.9), this vulne
Unauthenticated remote attackers can trigger complete database overwrites, server-side file reads, and SSRF attacks agai
The Kubernetes integration in GitLab Enterprise Edition 11.x before 11.2.8, 11.3.x before 11.3.9, and 11.4.x before 11.4
Fluentd configuration injection in the kube-logging Logging operator before 6.6.0 allows a namespace-scoped user who can
Kyverno Kubernetes policy engine prior to 1.x has a privilege escalation vulnerability (CVSS 9.9) allowing policy bypass
Same technique Denial Of Service
View allVendor StatusVendor
SUSE
Severity: Moderate| Product | Status |
|---|---|
| SUSE Linux Enterprise Server 16.1 | Affected |
| SUSE Linux Enterprise Server for SAP applications 16.1 | Affected |
| SUSE Linux Enterprise Module for Package Hub 15 SP5 | Affected |
| SUSE Linux Enterprise Module for Package Hub 15 SP6 | Affected |
| openSUSE Leap 15.5 | Affected |
| openSUSE Leap 15.6 | Affected |
Share
External POC / Exploit Code
Leaving vuln.today
GHSA-cwxq-rc9x-2jvv