Infra Audit4 min readUpdated November 4, 2026

One Open Port Reads Your Whole Cluster

The kubelet read-only port is deprecated and unauthenticated. If it answers, a stranger reads every pod's name, image and environment variables in one request.

curl http://NODE_IP:10255/pods with no credentials. A 200 with pod JSON means anonymous read of the entire workload inventory, including env vars that often hold secrets.

GET http://NODE_IP:10255/pods returns JSON with every pod on the node: names, namespaces, images, and the full environment of every container. Environment variables are where teams put database URLs, API keys and tokens. One unauthenticated request hands over the map of the workload and a pile of credentials.

What one request returns

GET http://NODE_IP:10255/pods returns JSON with every pod on the node: names, namespaces, images, and the full environment of every container. Environment variables are where teams put database URLs, API keys and tokens. One unauthenticated request hands over the map of the workload and a pile of credentials.
GET http://NODE_IP:10255/pods returns JSON with every pod on the node: names, namespaces, images, and the full environment of every container. Environment variables are where teams put database URLs, API keys and tokens. One unauthenticated request hands over the map of the workload and a pile of credentials. No auth, no token, no log the attacker needs to evade.

Why it still exists

The port is a legacy monitoring interface from before metrics-server. Kubernetes deprecated it years ago, and managed distributions close it by default. It survives on self-managed and kubeadm clusters where an old flag or an old playbook carried forward. The audit checks every node IP, because one forgotten node is enough.
The port is a legacy monitoring interface from before metrics-server. Kubernetes deprecated it years ago, and managed distributions close it by default. It survives on self-managed and kubeadm clusters where an old flag or an old playbook carried forward. The audit checks every node IP, because one forgotten node is enough.

The check and the fix

kubectl get nodes -o wide lists node IPs. The probe is one curl per node, status code only. A 200 is a confirmed P0. The fix is --read-only-port=0 in the kubelet flags, a restart of the kubelet, and a re-run of the same curl expecting a timeout. The whole cycle is minutes per node.
kubectl get nodes -o wide lists node IPs. The probe is one curl per node, status code only. A 200 is a confirmed P0. The fix is --read-only-port=0 in the kubelet flags, a restart of the kubelet, and a re-run of the same curl expecting a timeout. The whole cycle is minutes per node.

If it stays

Anyone with network reachability to the node, including a compromised pod in the same cluster, reads every credential in every environment variable. That is the pivot from one vulnerable app to the whole workload. The exposure window started when the cluster was provisioned, not when the audit found it.
Anyone with network reachability to the node, including a compromised pod in the same cluster, reads every credential in every environment variable. That is the pivot from one vulnerable app to the whole workload. The exposure window started when the cluster was provisioned, not when the audit found it.

4 Tips to Get Started

1

Check every node, not just the control plane. The kubelet runs on all of them.

2

The port is deprecated: if it answers at all, that is the finding. There is no safe configuration for it.

3

Env vars are the payload: database URLs, API keys, tokens. One request, all of them.

4

Fix is a kubelet flag: --read-only-port=0. Then re-run the curl and expect a timeout.

Ready to Stop Worrying About Infra?

Knowledge is the first step. Get a free 1-hour diagnostic and see where your infrastructure leaks time, money, and focus.

R

Ron Cohen — DevOps engineer & founder, roqy.io

Content reviewed by the roqy.io team. Our guides are based on publicly available data.

Disclaimer: This content is for informational and educational purposes only. It does not constitute professional advice or a guarantee of specific results. Infrastructure needs vary by team, stack, and stage. Consult a qualified engineer for advice tailored to your situation.

Frequently Asked Questions

What is the kubelet read-only port 10255?

An unauthenticated HTTP endpoint that returns every pod and its environment variables. If it is open, anyone who can reach the node reads the whole workload inventory with no credentials at all. It is deprecated but still enabled on many clusters.

How do I check if port 10255 is open?

kubectl get nodes -o wide gives every node IP, then curl http://NODE_IP:10255/pods from a network position that can reach it. A 200 with pod JSON is the finding. If the port is closed or firewalled, the request times out, which is the good outcome.

How do I disable the kubelet read-only port?

Set --read-only-port=0 in the kubelet configuration, or remove the flag if the default in your distribution is already 0. On managed clusters like EKS and GKE the port is normally closed; the finding appears mostly on self-managed or kubeadm clusters.

Get the DevOps Ecosystem Behind You

One accountable engineer. Full platform behind him. Month-to-month, no lock-in.