VYPR
Low severity2.7GHSA Advisory· Published Apr 22, 2024· Updated Apr 15, 2026

CVE-2024-3177

CVE-2024-3177

Description

A security issue was discovered in Kubernetes where users may be able to launch containers that bypass the mountable secrets policy enforced by the ServiceAccount admission plugin when using containers, init containers, and ephemeral containers with the envFrom field populated. The policy ensures pods running with a service account may only reference secrets specified in the service account’s secrets field. Kubernetes clusters are only affected if the ServiceAccount admission plugin and the kubernetes.io/enforce-mountable-secrets annotation are used together with containers, init containers, and ephemeral containers with the envFrom field populated.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
k8s.io/kubernetesGo
< 1.27.131.27.13
k8s.io/kubernetesGo
>= 1.29.0, < 1.29.41.29.4
k8s.io/kubernetesGo
>= 1.28.0, < 1.28.91.28.9

Affected products

1

Patches

3
f9fb6cf52a76

Merge pull request #124326 from ritazh/automated-cherry-pick-of-#124322-upstream-release-1.28

https://github.com/kubernetes/kubernetesKubernetes Prow RobotApr 16, 2024via ghsa
2 files changed · +132 11
  • plugin/pkg/admission/serviceaccount/admission.go+21 0 modified
    @@ -337,6 +337,13 @@ func (s *Plugin) limitSecretReferences(serviceAccount *corev1.ServiceAccount, po
     				}
     			}
     		}
    +		for _, envFrom := range container.EnvFrom {
    +			if envFrom.SecretRef != nil {
    +				if !mountableSecrets.Has(envFrom.SecretRef.Name) {
    +					return fmt.Errorf("init container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name)
    +				}
    +			}
    +		}
     	}
     
     	for _, container := range pod.Spec.Containers {
    @@ -347,6 +354,13 @@ func (s *Plugin) limitSecretReferences(serviceAccount *corev1.ServiceAccount, po
     				}
     			}
     		}
    +		for _, envFrom := range container.EnvFrom {
    +			if envFrom.SecretRef != nil {
    +				if !mountableSecrets.Has(envFrom.SecretRef.Name) {
    +					return fmt.Errorf("container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name)
    +				}
    +			}
    +		}
     	}
     
     	// limit pull secret references as well
    @@ -388,6 +402,13 @@ func (s *Plugin) limitEphemeralContainerSecretReferences(pod *api.Pod, a admissi
     				}
     			}
     		}
    +		for _, envFrom := range container.EnvFrom {
    +			if envFrom.SecretRef != nil {
    +				if !mountableSecrets.Has(envFrom.SecretRef.Name) {
    +					return fmt.Errorf("ephemeral container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name)
    +				}
    +			}
    +		}
     	}
     	return nil
     }
    
  • plugin/pkg/admission/serviceaccount/admission_test.go+111 11 modified
    @@ -520,6 +520,25 @@ func TestAllowsReferencedSecret(t *testing.T) {
     		t.Errorf("Unexpected error: %v", err)
     	}
     
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			Containers: []api.Container{
    +				{
    +					Name: "container-1",
    +					EnvFrom: []api.EnvFromSource{
    +						{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +				},
    +			},
    +		},
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
    +	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil {
    +		t.Errorf("Unexpected error: %v", err)
    +	}
    +
     	pod2 = &api.Pod{
     		Spec: api.PodSpec{
     			InitContainers: []api.Container{
    @@ -544,6 +563,25 @@ func TestAllowsReferencedSecret(t *testing.T) {
     		t.Errorf("Unexpected error: %v", err)
     	}
     
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			InitContainers: []api.Container{
    +				{
    +					Name: "container-1",
    +					EnvFrom: []api.EnvFromSource{
    +						{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +				},
    +			},
    +		},
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
    +	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil {
    +		t.Errorf("Unexpected error: %v", err)
    +	}
    +
     	pod2 = &api.Pod{
     		Spec: api.PodSpec{
     			ServiceAccountName: DefaultServiceAccountName,
    @@ -571,6 +609,28 @@ func TestAllowsReferencedSecret(t *testing.T) {
     	if err := admit.Validate(context.TODO(), attrs, nil); err != nil {
     		t.Errorf("Unexpected error: %v", err)
     	}
    +
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			ServiceAccountName: DefaultServiceAccountName,
    +			EphemeralContainers: []api.EphemeralContainer{
    +				{
    +					EphemeralContainerCommon: api.EphemeralContainerCommon{
    +						Name: "container-2",
    +						EnvFrom: []api.EnvFromSource{{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +					},
    +				},
    +			},
    +		},
    +	}
    +	// validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers"
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "ephemeralcontainers", admission.Update, &metav1.UpdateOptions{}, false, nil)
    +	if err := admit.Validate(context.TODO(), attrs, nil); err != nil {
    +		t.Errorf("Unexpected error: %v", err)
    +	}
     }
     
     func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
    @@ -627,25 +687,20 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
     
     	pod2 = &api.Pod{
     		Spec: api.PodSpec{
    -			InitContainers: []api.Container{
    +			Containers: []api.Container{
     				{
     					Name: "container-1",
    -					Env: []api.EnvVar{
    +					EnvFrom: []api.EnvFromSource{
     						{
    -							Name: "env-1",
    -							ValueFrom: &api.EnvVarSource{
    -								SecretKeyRef: &api.SecretKeySelector{
    -									LocalObjectReference: api.LocalObjectReference{Name: "foo"},
    -								},
    -							},
    -						},
    -					},
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
     				},
     			},
     		},
     	}
     	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
    -	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envVar") {
    +	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") {
     		t.Errorf("Unexpected error: %v", err)
     	}
     
    @@ -678,6 +733,30 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
     		t.Errorf("validate only enforces restrictions on secret mounts when operation==create and subresource==''. Unexpected error: %v", err)
     	}
     
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			ServiceAccountName: DefaultServiceAccountName,
    +			InitContainers: []api.Container{
    +				{
    +					Name: "container-1",
    +					EnvFrom: []api.EnvFromSource{
    +						{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +				},
    +			},
    +		},
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil)
    +	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil {
    +		t.Errorf("admit only enforces restrictions on secret mounts when operation==create. Unexpected error: %v", err)
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
    +	if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") {
    +		t.Errorf("validate only enforces restrictions on secret mounts when operation==create and subresource==''. Unexpected error: %v", err)
    +	}
    +
     	pod2 = &api.Pod{
     		Spec: api.PodSpec{
     			ServiceAccountName: DefaultServiceAccountName,
    @@ -708,6 +787,27 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
     	if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envVar") {
     		t.Errorf("validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers. Unexpected error: %v", err)
     	}
    +
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			ServiceAccountName: DefaultServiceAccountName,
    +			EphemeralContainers: []api.EphemeralContainer{
    +				{
    +					EphemeralContainerCommon: api.EphemeralContainerCommon{
    +						Name: "container-2",
    +						EnvFrom: []api.EnvFromSource{{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +					},
    +				},
    +			},
    +		},
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "ephemeralcontainers", admission.Update, &metav1.UpdateOptions{}, false, nil)
    +	if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") {
    +		t.Errorf("validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers. Unexpected error: %v", err)
    +	}
     }
     
     func TestAllowUnreferencedSecretVolumesForPermissiveSAs(t *testing.T) {
    
a619ca3fd3ee

Merge pull request #124327 from ritazh/automated-cherry-pick-of-#124322-upstream-release-1.29

https://github.com/kubernetes/kubernetesKubernetes Prow RobotApr 16, 2024via ghsa
2 files changed · +132 11
  • plugin/pkg/admission/serviceaccount/admission.go+21 0 modified
    @@ -337,6 +337,13 @@ func (s *Plugin) limitSecretReferences(serviceAccount *corev1.ServiceAccount, po
     				}
     			}
     		}
    +		for _, envFrom := range container.EnvFrom {
    +			if envFrom.SecretRef != nil {
    +				if !mountableSecrets.Has(envFrom.SecretRef.Name) {
    +					return fmt.Errorf("init container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name)
    +				}
    +			}
    +		}
     	}
     
     	for _, container := range pod.Spec.Containers {
    @@ -347,6 +354,13 @@ func (s *Plugin) limitSecretReferences(serviceAccount *corev1.ServiceAccount, po
     				}
     			}
     		}
    +		for _, envFrom := range container.EnvFrom {
    +			if envFrom.SecretRef != nil {
    +				if !mountableSecrets.Has(envFrom.SecretRef.Name) {
    +					return fmt.Errorf("container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name)
    +				}
    +			}
    +		}
     	}
     
     	// limit pull secret references as well
    @@ -388,6 +402,13 @@ func (s *Plugin) limitEphemeralContainerSecretReferences(pod *api.Pod, a admissi
     				}
     			}
     		}
    +		for _, envFrom := range container.EnvFrom {
    +			if envFrom.SecretRef != nil {
    +				if !mountableSecrets.Has(envFrom.SecretRef.Name) {
    +					return fmt.Errorf("ephemeral container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name)
    +				}
    +			}
    +		}
     	}
     	return nil
     }
    
  • plugin/pkg/admission/serviceaccount/admission_test.go+111 11 modified
    @@ -520,6 +520,25 @@ func TestAllowsReferencedSecret(t *testing.T) {
     		t.Errorf("Unexpected error: %v", err)
     	}
     
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			Containers: []api.Container{
    +				{
    +					Name: "container-1",
    +					EnvFrom: []api.EnvFromSource{
    +						{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +				},
    +			},
    +		},
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
    +	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil {
    +		t.Errorf("Unexpected error: %v", err)
    +	}
    +
     	pod2 = &api.Pod{
     		Spec: api.PodSpec{
     			InitContainers: []api.Container{
    @@ -544,6 +563,25 @@ func TestAllowsReferencedSecret(t *testing.T) {
     		t.Errorf("Unexpected error: %v", err)
     	}
     
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			InitContainers: []api.Container{
    +				{
    +					Name: "container-1",
    +					EnvFrom: []api.EnvFromSource{
    +						{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +				},
    +			},
    +		},
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
    +	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil {
    +		t.Errorf("Unexpected error: %v", err)
    +	}
    +
     	pod2 = &api.Pod{
     		Spec: api.PodSpec{
     			ServiceAccountName: DefaultServiceAccountName,
    @@ -571,6 +609,28 @@ func TestAllowsReferencedSecret(t *testing.T) {
     	if err := admit.Validate(context.TODO(), attrs, nil); err != nil {
     		t.Errorf("Unexpected error: %v", err)
     	}
    +
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			ServiceAccountName: DefaultServiceAccountName,
    +			EphemeralContainers: []api.EphemeralContainer{
    +				{
    +					EphemeralContainerCommon: api.EphemeralContainerCommon{
    +						Name: "container-2",
    +						EnvFrom: []api.EnvFromSource{{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +					},
    +				},
    +			},
    +		},
    +	}
    +	// validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers"
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "ephemeralcontainers", admission.Update, &metav1.UpdateOptions{}, false, nil)
    +	if err := admit.Validate(context.TODO(), attrs, nil); err != nil {
    +		t.Errorf("Unexpected error: %v", err)
    +	}
     }
     
     func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
    @@ -627,25 +687,20 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
     
     	pod2 = &api.Pod{
     		Spec: api.PodSpec{
    -			InitContainers: []api.Container{
    +			Containers: []api.Container{
     				{
     					Name: "container-1",
    -					Env: []api.EnvVar{
    +					EnvFrom: []api.EnvFromSource{
     						{
    -							Name: "env-1",
    -							ValueFrom: &api.EnvVarSource{
    -								SecretKeyRef: &api.SecretKeySelector{
    -									LocalObjectReference: api.LocalObjectReference{Name: "foo"},
    -								},
    -							},
    -						},
    -					},
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
     				},
     			},
     		},
     	}
     	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
    -	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envVar") {
    +	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") {
     		t.Errorf("Unexpected error: %v", err)
     	}
     
    @@ -678,6 +733,30 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
     		t.Errorf("validate only enforces restrictions on secret mounts when operation==create and subresource==''. Unexpected error: %v", err)
     	}
     
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			ServiceAccountName: DefaultServiceAccountName,
    +			InitContainers: []api.Container{
    +				{
    +					Name: "container-1",
    +					EnvFrom: []api.EnvFromSource{
    +						{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +				},
    +			},
    +		},
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil)
    +	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil {
    +		t.Errorf("admit only enforces restrictions on secret mounts when operation==create. Unexpected error: %v", err)
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
    +	if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") {
    +		t.Errorf("validate only enforces restrictions on secret mounts when operation==create and subresource==''. Unexpected error: %v", err)
    +	}
    +
     	pod2 = &api.Pod{
     		Spec: api.PodSpec{
     			ServiceAccountName: DefaultServiceAccountName,
    @@ -708,6 +787,27 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
     	if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envVar") {
     		t.Errorf("validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers. Unexpected error: %v", err)
     	}
    +
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			ServiceAccountName: DefaultServiceAccountName,
    +			EphemeralContainers: []api.EphemeralContainer{
    +				{
    +					EphemeralContainerCommon: api.EphemeralContainerCommon{
    +						Name: "container-2",
    +						EnvFrom: []api.EnvFromSource{{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +					},
    +				},
    +			},
    +		},
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "ephemeralcontainers", admission.Update, &metav1.UpdateOptions{}, false, nil)
    +	if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") {
    +		t.Errorf("validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers. Unexpected error: %v", err)
    +	}
     }
     
     func TestAllowUnreferencedSecretVolumesForPermissiveSAs(t *testing.T) {
    
7c861b1ecad9

Merge pull request #124325 from ritazh/automated-cherry-pick-of-#124322-upstream-release-1.27

https://github.com/kubernetes/kubernetesKubernetes Prow RobotApr 16, 2024via ghsa
2 files changed · +132 11
  • plugin/pkg/admission/serviceaccount/admission.go+21 0 modified
    @@ -337,6 +337,13 @@ func (s *Plugin) limitSecretReferences(serviceAccount *corev1.ServiceAccount, po
     				}
     			}
     		}
    +		for _, envFrom := range container.EnvFrom {
    +			if envFrom.SecretRef != nil {
    +				if !mountableSecrets.Has(envFrom.SecretRef.Name) {
    +					return fmt.Errorf("init container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name)
    +				}
    +			}
    +		}
     	}
     
     	for _, container := range pod.Spec.Containers {
    @@ -347,6 +354,13 @@ func (s *Plugin) limitSecretReferences(serviceAccount *corev1.ServiceAccount, po
     				}
     			}
     		}
    +		for _, envFrom := range container.EnvFrom {
    +			if envFrom.SecretRef != nil {
    +				if !mountableSecrets.Has(envFrom.SecretRef.Name) {
    +					return fmt.Errorf("container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name)
    +				}
    +			}
    +		}
     	}
     
     	// limit pull secret references as well
    @@ -388,6 +402,13 @@ func (s *Plugin) limitEphemeralContainerSecretReferences(pod *api.Pod, a admissi
     				}
     			}
     		}
    +		for _, envFrom := range container.EnvFrom {
    +			if envFrom.SecretRef != nil {
    +				if !mountableSecrets.Has(envFrom.SecretRef.Name) {
    +					return fmt.Errorf("ephemeral container %s with envFrom referencing secret.secretName=\"%s\" is not allowed because service account %s does not reference that secret", container.Name, envFrom.SecretRef.Name, serviceAccount.Name)
    +				}
    +			}
    +		}
     	}
     	return nil
     }
    
  • plugin/pkg/admission/serviceaccount/admission_test.go+111 11 modified
    @@ -521,6 +521,25 @@ func TestAllowsReferencedSecret(t *testing.T) {
     		t.Errorf("Unexpected error: %v", err)
     	}
     
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			Containers: []api.Container{
    +				{
    +					Name: "container-1",
    +					EnvFrom: []api.EnvFromSource{
    +						{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +				},
    +			},
    +		},
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
    +	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil {
    +		t.Errorf("Unexpected error: %v", err)
    +	}
    +
     	pod2 = &api.Pod{
     		Spec: api.PodSpec{
     			InitContainers: []api.Container{
    @@ -545,6 +564,25 @@ func TestAllowsReferencedSecret(t *testing.T) {
     		t.Errorf("Unexpected error: %v", err)
     	}
     
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			InitContainers: []api.Container{
    +				{
    +					Name: "container-1",
    +					EnvFrom: []api.EnvFromSource{
    +						{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +				},
    +			},
    +		},
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
    +	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil {
    +		t.Errorf("Unexpected error: %v", err)
    +	}
    +
     	pod2 = &api.Pod{
     		Spec: api.PodSpec{
     			ServiceAccountName: DefaultServiceAccountName,
    @@ -572,6 +610,28 @@ func TestAllowsReferencedSecret(t *testing.T) {
     	if err := admit.Validate(context.TODO(), attrs, nil); err != nil {
     		t.Errorf("Unexpected error: %v", err)
     	}
    +
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			ServiceAccountName: DefaultServiceAccountName,
    +			EphemeralContainers: []api.EphemeralContainer{
    +				{
    +					EphemeralContainerCommon: api.EphemeralContainerCommon{
    +						Name: "container-2",
    +						EnvFrom: []api.EnvFromSource{{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +					},
    +				},
    +			},
    +		},
    +	}
    +	// validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers"
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "ephemeralcontainers", admission.Update, &metav1.UpdateOptions{}, false, nil)
    +	if err := admit.Validate(context.TODO(), attrs, nil); err != nil {
    +		t.Errorf("Unexpected error: %v", err)
    +	}
     }
     
     func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
    @@ -628,25 +688,20 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
     
     	pod2 = &api.Pod{
     		Spec: api.PodSpec{
    -			InitContainers: []api.Container{
    +			Containers: []api.Container{
     				{
     					Name: "container-1",
    -					Env: []api.EnvVar{
    +					EnvFrom: []api.EnvFromSource{
     						{
    -							Name: "env-1",
    -							ValueFrom: &api.EnvVarSource{
    -								SecretKeyRef: &api.SecretKeySelector{
    -									LocalObjectReference: api.LocalObjectReference{Name: "foo"},
    -								},
    -							},
    -						},
    -					},
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
     				},
     			},
     		},
     	}
     	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
    -	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envVar") {
    +	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") {
     		t.Errorf("Unexpected error: %v", err)
     	}
     
    @@ -679,6 +734,30 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
     		t.Errorf("validate only enforces restrictions on secret mounts when operation==create and subresource==''. Unexpected error: %v", err)
     	}
     
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			ServiceAccountName: DefaultServiceAccountName,
    +			InitContainers: []api.Container{
    +				{
    +					Name: "container-1",
    +					EnvFrom: []api.EnvFromSource{
    +						{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +				},
    +			},
    +		},
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Update, &metav1.UpdateOptions{}, false, nil)
    +	if err := admissiontesting.WithReinvocationTesting(t, admit).Admit(context.TODO(), attrs, nil); err != nil {
    +		t.Errorf("admit only enforces restrictions on secret mounts when operation==create. Unexpected error: %v", err)
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "", admission.Create, &metav1.CreateOptions{}, false, nil)
    +	if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") {
    +		t.Errorf("validate only enforces restrictions on secret mounts when operation==create and subresource==''. Unexpected error: %v", err)
    +	}
    +
     	pod2 = &api.Pod{
     		Spec: api.PodSpec{
     			ServiceAccountName: DefaultServiceAccountName,
    @@ -709,6 +788,27 @@ func TestRejectsUnreferencedSecretVolumes(t *testing.T) {
     	if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envVar") {
     		t.Errorf("validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers. Unexpected error: %v", err)
     	}
    +
    +	pod2 = &api.Pod{
    +		Spec: api.PodSpec{
    +			ServiceAccountName: DefaultServiceAccountName,
    +			EphemeralContainers: []api.EphemeralContainer{
    +				{
    +					EphemeralContainerCommon: api.EphemeralContainerCommon{
    +						Name: "container-2",
    +						EnvFrom: []api.EnvFromSource{{
    +							SecretRef: &api.SecretEnvSource{
    +								LocalObjectReference: api.LocalObjectReference{
    +									Name: "foo"}}}},
    +					},
    +				},
    +			},
    +		},
    +	}
    +	attrs = admission.NewAttributesRecord(pod2, nil, api.Kind("Pod").WithVersion("version"), ns, "myname", api.Resource("pods").WithVersion("version"), "ephemeralcontainers", admission.Update, &metav1.UpdateOptions{}, false, nil)
    +	if err := admit.Validate(context.TODO(), attrs, nil); err == nil || !strings.Contains(err.Error(), "with envFrom") {
    +		t.Errorf("validate enforces restrictions on secret mounts when operation==update and subresource==ephemeralcontainers. Unexpected error: %v", err)
    +	}
     }
     
     func TestAllowUnreferencedSecretVolumesForPermissiveSAs(t *testing.T) {
    

Vulnerability mechanics

Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

13

News mentions

0

No linked articles in our index yet.