Kubetier
← Permission Reference
T0

get nodes/proxy

Lets an attacker execute commands in any pod on the node.

WebSocket exec handshakes over HTTP GET map to the get verb, so get alone on nodes/proxy bypasses pods/exec and the audit log.

Proxies to the kubelet API on port 10250.

It is also the trigger half of fake-Node SSRF, paired with create on nodes.

API Group
(core)
Scope
cluster
Audit Level
RequestResponse

Escalation Paths

  1. Connect to the exec endpoint via WebSocket.

    The HTTP GET upgrade handshake maps to the 'get' verb at the kubelet, so get nodes/proxy alone is sufficient

  2. The kubelet never performs a secondary 'create' check for the exec operation that follows the handshake

  3. Path A, via API server proxy, uses curl with Upgrade: websocket headers.

    Auth is logged as a nodes/proxy check only, the actual exec is invisible to audit

  4. Path B is direct to the kubelet on port 10250, using websocat wss://$NODE_IP:10250/exec/....

    Zero API server audit events are generated

  5. Execute arbitrary commands in any pod on the node, and steal service account tokens to pivot

Additional rights needed:

none
✕ Won't Fix

Note:

There is no CVE.

The security team calls this working as intended (Jan 2026).

The WebSocket exec bypass has no fix.

KEP-2862 adds narrower subresources but does not cover exec, attach or portforward.

K8s docs ↗
  1. Register a fake Node object with status.addresses[InternalIP] = API server internal IP and daemonEndpoints.kubeletEndpoint.Port = 6443

  2. Proxy a request through the fake node by running kubectl get --raw /api/v1/nodes/evil-node/proxy/api/v1/secrets

  3. The API server proxies outbound to that address using its apiserver-kubelet-client certificate, so it authenticates to itself

  4. Before kubeadm 1.29 the certificate carried O=system:masters.

    From 1.29 it carried O=kubeadm:cluster-admins, a group bound to cluster-admin, so the inner request still returned full cluster access

  5. Current kubeadm drops the certificate's Organization and binds the User named by its CommonName to the system:kubelet-api-admin ClusterRole, so the request reaches the node API, not cluster-admin

  6. The redirection itself is unchanged by that fix, so the API server can still be pointed at an attacker-chosen address

  7. Post-fix, the gain is network position rather than RBAC, since triggering it already requires get on nodes/proxy.

    The API server reaches addresses the caller cannot, under its own identity

  8. On a managed control plane the fabricated Node is deleted by cloud node lifecycle within seconds, and the dial to the API server own address does not complete

Additional rights needed:

✓ Patched: kubeadm 1.33.12 / 1.34.8 / 1.35.5 / 1.36.1

Note:

Those releases narrow the certificate to system:kubelet-api-admin, which removes the cluster-admin outcome but not the redirection.

kubernetes#119270 is still open, reopened for audit re-evaluation.

1.32 reached end of life first, so it stays vulnerable.

No CVE covers this path.

K8s docs ↗
  1. Register a fake Node with a DNS rebinding hostname that initially resolves to a valid public IP

  2. API server checks isProxyableHost before connecting.

    At check time, DNS resolves to the allowed IP

  3. By connect time, DNS flips to 127.0.0.1 or 169.254.x.x.

    The blocklist check is not re-run (TOCTOU)

  4. SSRF reaches loopback services such as kube-proxy :10249 configz, etcd :2379, and control-plane localhost ports

Additional rights needed:

✕ Won't FixCVE-2020-8562won't fix↗

Note:

This is a wontFix.

Fixing requires IP pinning between check and connect, which breaks split-horizon DNS.

Mitigation is dnsmasq min-cache-ttl.

K8s docs ↗
K8s docs ↗