How an aggregated API server context desync in k8s.io/apiserver allowed namespace-limited users to bypass RBAC and execute cluster-admin actions.
Imagine a shared building where you only have a key to Apartment 4. You go to the front desk and ask for maintenance service. The receptionist forgets to write your apartment number on the work order. The maintenance staff assumes the work order is for the penthouse suite, letting you walk right into the master control room of the entire building.
An attacker has access only to a low-privileged namespace (e.g. dev).
The attacker issues a request to an aggregated API endpoint omitting namespace parameters.
The API proxy misinterprets the empty namespace as an authorization request for cluster-wide scope.
The attacker accesses cluster secrets and mounts host root volumes across all worker nodes.
Apresentado em código-fonte legível de alto nível (sem assembly bruto ou diffs binários).
// VULNERABLE: k8s.io/apiserver/pkg/endpoints/request/context.go
func NamespaceValue(ctx context.Context) string {
// ROOT CAUSE:
// If request context lacks explicit namespace header,
// returns empty string ("") which aggregated handlers interpret as CLUSTER-SCOPED!
val, ok := ctx.Value(namespaceKey).(string)
if !ok {
return "" // Inadvertently grants cluster-scoped evaluation!
}
return val;
}
// SECURE: k8s.io/apiserver/pkg/endpoints/request/context.go patch
func NamespaceValue(ctx context.Context) (string, error) {
val, ok := ctx.Value(namespaceKey).(string)
// 1. Explicitly reject missing namespace for namespace-scoped endpoints
if !ok || val == "" {
return "", fmt.Errorf("authorization context: namespace cannot be empty")
}
// 2. Return strictly verified namespace identifier
return val, nil
}