kube-hunter Tutorial: Scan the Kubernetes Attack Surface

Tested on Kali GNU/Linux Rolling 2026.2 (kali-rolling)
Package kube-hunter 0.6.8
kubectl (via k3s)
Lab environment Pentest lab
Cert prep CompTIA PenTest+ PT0-003 — Domain 3 (Vulnerability Discovery) and Domain 4e (cloud and container)
Privilege Normal user for remote and interface scans; Kubernetes credentials with permission to create a Job and read pod logs for the in-cluster scan
Scope Install kube-hunter, list hunters, run passive remote and interface scans, interpret and manually validate findings, run an in-pod Job, understand active hunting risks, export JSON, and compare with kube-bench and Trivy. Does not cover building a cluster from scratch, CIS full remediation, image scanning, or treating kube-hunter as a complete security program.
Related guides Container scanning with Trivy and Grype
OpenVAS / Greenbone tutorial
Vulnerability scanning concepts
Install Kubernetes with kubeadm
Short on time?Beta Get the gist of this 15-minute read in seconds, then ask follow-up questions

kube-hunter answers a different question than most Kubernetes scanners: from this network location, what Kubernetes services and weaknesses could an attacker discover? On PenTest+, that vantage-point mindset shows up in Domain 3 scanner selection and again when Domain 4e covers container and Kubernetes attack surfaces.

IMPORTANT
Run kube-hunter only against clusters covered by your rules of engagement. Aqua marks the project as not under active development and points teams toward Trivy for ongoing Kubernetes misconfiguration and KBOM work. kube-hunter is still useful for learning and demonstrating attacker vantage points, but it should not be presented as a current all-purpose Kubernetes security scanner. The practical idea that still matters: where you run the scanner changes what it can see.

What kube-hunter scans in a Kubernetes cluster

Tool Purpose
kube-hunter Attacker-view attack-surface probing
kube-bench CIS configuration audit
Trivy CVEs and configuration / misconfiguration scanning

Use kube-hunter when you need an attacker-eye view from a chosen network location. Save image scanning, CIS node audits, and ongoing posture checks for the comparison section later.


Choose the kube-hunter vantage point

Official docs describe several places to run the tool. Results change with each place:

kube-hunter vantage points: remote outside the cluster, host interface scan, and in-pod compromised workload view

Vantage Flag Meaning
Remote target --remote Probe one or more target hosts by IP or DNS name
Local interfaces --interface Discover across networks visible to this host
Network range --cidr Scan a specified subnet
Inside a pod --pod Model a compromised workload with a service account token

Remember two points before you compare reports:

  • A clean remote scan does not prove a compromised pod would see the same surface
  • Always record where you ran kube-hunter next to the findings

Install kube-hunter

kube-hunter is an older Python project. A virtual environment avoids modifying the system Python, and this guide pins the tested 0.6.8 release.

On this Kali lab I installed that release from PyPI:

bash
python3 -m venv ~/kube-hunter-venv

The command exits with no output when the environment is created. Install the pinned package next:

bash
~/kube-hunter-venv/bin/pip install 'kube-hunter==0.6.8'

pip prints package progress as it installs. When it finishes, confirm the CLI is available:

bash
~/kube-hunter-venv/bin/kube-hunter --help | head -20
output
usage: kube-hunter [-h] [--list] [--interface] [--pod] [--quick]
                   [--include-patched-versions] [--cidr CIDR] [--mapping]
                   [--remote HOST [HOST ...]] [-c HUNTERS [HUNTERS ...]]
                   [--raw-hunter-names] [--k8s-auto-discover-nodes]
                   [--service-account-token JWT_TOKEN]
                   [--kubeconfig KUBECONFIG] [--active] [--enable-cve-hunting]
                   [--log LOGLEVEL] [--log-file LOG_FILE] [--report REPORT]
                   [--dispatch DISPATCH] [--statistics]
                   [--network-timeout NETWORK_TIMEOUT]
                   [--num-worker-threads NUM_WORKER_THREADS]

The help text lists remote, interface, pod, active, and report options used later. Put the binary on your PATH with a symlink, or keep calling the full venv path. Container and Job forms also exist (aquasec/kube-hunter:0.6.8). This article uses pip for the remote and interface steps and the official Job for --pod.


List available hunters before running them

A hunter is one discovery or check (API discovery, kubelet ports, etcd, and so on). The list changes over time, so do not memorize it from a blog. Ask kube-hunter:

bash
kube-hunter --list
output
Passive Hunters:
----------------
* API Service Discovery
  Checks for the existence of K8s API Services

* K8s Dashboard Discovery
  Checks for the existence of a Dashboard

* Etcd service
  check for the existence of etcd service

* Kubelet Discovery
  Checks for the existence of a Kubelet service, and its open ports

* Port Scanning
  Scans Kubernetes known ports to determine open endpoints for discovery
…

On 0.6.8 the passive list is tens of hunters. To include active hunters in the listing (review only — do not enable them yet):

bash
kube-hunter --list --active

The combined list adds hunters that can change cluster state. Read that list before you ever add --active to a real scan. Upstream keeps the current exhaustive set in the kube-hunter repository; the active-hunting section below covers the risk rules.


Run a passive remote kube-hunter scan

Start outside the cluster. Pick one API or node address you are allowed to probe and store it in a variable:

bash
API_HOST=10.0.2.15

Shell assignment prints nothing. On this lab that address is the Kubernetes node IP. Your value may be a load balancer, control-plane IP, or DNS name.

Run a passive remote hunt (default hunters, no --active):

bash
kube-hunter --remote "$API_HOST" --report plain --log WARNING
output
Nodes
+-------------+-----------+
| TYPE        | LOCATION  |
+-------------+-----------+
| Node/Master | 10.0.2.15 |
+-------------+-----------+

Detected Services
+----------------------+-----------------+----------------------+
| SERVICE              | LOCATION        | DESCRIPTION          |
+----------------------+-----------------+----------------------+
| Unrecognized K8s API | 10.0.2.15:6443  | A Kubernetes API     |
|                      |                 | service              |
+----------------------+-----------------+----------------------+
| Kubelet API          | 10.0.2.15:10250 | The Kubelet is the   |
|                      |                 | main component in    |
|                      |                 | every Node, all pod  |
|                      |                 | operations goes      |
|                      |                 | through the kubelet  |
+----------------------+-----------------+----------------------+

No vulnerabilities were found

What the remote report means:

  • kube-hunter found the API on 6443 and the kubelet on 10250
  • it did not open a vulnerability row from this remote vantage point
  • “No vulnerabilities were found” means no hunter raised a finding from here, not that the cluster is safe

Next, compare with a host-network view on the same machine.


Interpret kube-hunter findings

Run an interface scan so kube-hunter probes addresses visible on local interfaces (pod CIDR, node IP, and so on):

bash
kube-hunter --interface --report plain --log WARNING

Trimmed findings from this lab (duplicate rows for the same location removed):

output
Vulnerabilities
For further information about a vulnerability, search its ID in:
https://avd.aquasec.com/
+--------+------------------+----------------------+----------------------+----------------------+------------+
| ID     | LOCATION         | MITRE CATEGORY       | VULNERABILITY        | DESCRIPTION          | EVIDENCE   |
+--------+------------------+----------------------+----------------------+----------------------+------------+
| KHV043 | 10.42.0.16:10250 | Initial Access //    | Cluster Health       | open /healthz        | status: ok |
|        |                  | General Sensitive    | Disclosure           | without auth         |            |
|        |                  | Information          |                      |                      |            |
| KHV036 | 10.42.0.16:10250 | Initial Access //    | Anonymous            | kubelet may allow    |            |
|        |                  | Exposed sensitive    | Authentication       | unauthenticated      |            |
|        |                  | interfaces           |                      | secure-port access   |            |
+--------+------------------+----------------------+----------------------+----------------------+------------+

Same cluster as the remote scan. Different vantage. New findings.

For each row, walk this checklist:

Question Why it matters
What was discovered? Port, handler (/healthz), anonymous kubelet, and so on
Where was it reachable from? Remote IP, pod network, or local-to-pod
Why does it matter? Information leak vs possible control of pods
Was authentication required? Evidence such as status: ok without credentials
What should I verify manually? Read-only HTTP checks, kubelet flags, who can reach the port
What control remediates it? Authn settings, bind addresses, host firewall / trusted networks
How do I retest? Same kube-hunter command and vantage after the fix

Do not treat a NetworkPolicy as a guaranteed control for node-local kubelet port 10250. Policy behavior for node and host-network traffic varies by CNI; verify with host firewall and kubelet bind settings as well.

Example: KHV043 Cluster Health Disclosure

  • Discovery: kubelet /healthz answered without authentication
  • Reachable from: addresses on the host/pod network (10.42.0.16:10250 here)
  • Why it matters: attackers learn component health without logging in
  • Verify: confirm which interfaces listen on 10250 and whether that network path is intentional
  • Remediate: review whether the kubelet health endpoint needs to be reachable from that network; restrict access to kubelet port 10250 to trusted sources and verify kubelet authentication / authorization configuration
  • Retest: rerun --interface (or --pod) and confirm the finding is gone

Example: KHV036 Anonymous Authentication

  • Discovery: kube-hunter reports that kubelet may accept anonymous access on the secure port
  • Why it matters: if anonymous access is real, worse cases can lead toward pod exec and host impact (active hunters try to prove that)
  • Do not jump straight to --active on a production cluster to “confirm”
IMPORTANT
kube-hunter 0.6.8 has an open upstream issue for possible KHV036 false positives. Manually verify anonymous kubelet access before reporting this as a vulnerability. A reachable 10250 endpoint or a kube-hunter row alone is not proof that anonymous API requests are authorized.

On this lab, a read-only unauthenticated request to /healthz returned 200, while /pods returned 403:

bash
curl -sk -o /dev/null -w "%{http_code}\n" "https://10.42.0.16:10250/healthz"
output
200

200 confirms /healthz answered without credentials. Next, ask whether anonymous clients can list pods on the same kubelet:

bash
curl -sk -o /dev/null -w "%{http_code}\n" "https://10.42.0.16:10250/pods"
output
403

How to read those codes:

  • 200 on a sensitive handler means the endpoint really answered without credentials
  • 401 or 403 means the anonymous request is not authorized; treat KHV036 as unverified until you confirm a real unauthorized success
  • Here /healthz supports the KHV043 disclosure finding, while /pods shows anonymous listing is forbidden — so do not report KHV036 as confirmed from the kube-hunter row alone

Look up VID details in the Aqua vulnerability knowledge base using the KHV… ID, and see upstream issue #548 for the KHV036 false-positive report.


Run kube-hunter from inside the cluster

An external clean result still leaves an open question: what if one application pod is compromised? The --pod mode answers that.

Download the upstream Job manifest with curl and pin the same 0.6.8 image tag:

bash
curl -sfL https://raw.githubusercontent.com/aquasecurity/kube-hunter/main/job.yaml -o kube-hunter-job.yaml

Confirm the Job args use --pod:

bash
grep -A6 'containers:' kube-hunter-job.yaml
output
      containers:
        - name: kube-hunter
          image: aquasec/kube-hunter:0.6.8
          command: ["kube-hunter"]
          args: ["--pod"]
      restartPolicy: Never

The image and --pod argument match an in-cluster hunt. Create the Job with kubectl apply:

bash
kubectl apply -f kube-hunter-job.yaml
output
job.batch/kube-hunter created

Kubernetes accepted the Job. When the pod finishes (kubectl get job kube-hunter shows a completion), read its report:

bash
kubectl logs job/kube-hunter

Trimmed vulnerability section from this lab’s Job (kubectl logs job/kube-hunter):

output
Vulnerabilities
For further information about a vulnerability, search its ID in:
https://avd.aquasec.com/
+--------+------------------+----------------------+----------------------+----------------------+------------+
| ID     | LOCATION         | MITRE CATEGORY       | VULNERABILITY        | DESCRIPTION          | EVIDENCE   |
+--------+------------------+----------------------+----------------------+----------------------+------------+
| None   | Local to Pod     | Lateral Movement //  | CAP_NET_RAW Enabled  | CAP_NET_RAW is       |            |
|        |                  | ARP poisoning and IP |                      | enabled by default   |            |
|        |                  | spoofing             |                      | for pods             |            |
| KHV043 | 10.42.0.16:10250 | Initial Access //    | Cluster Health       | open /healthz        | status: ok |
|        |                  | General Sensitive    | Disclosure           | without auth         |            |
|        |                  | Information          |                      |                      |            |
| KHV036 | 10.42.0.16:10250 | Initial Access //    | Anonymous            | kubelet may allow    |            |
|        |                  | Exposed sensitive    | Authentication       | unauthenticated      |            |
|        |                  | interfaces           |                      | secure-port access   |            |
| KHV002 | 10.43.0.1:443    | Initial Access //    | K8s Version          | /version returned    | v1.36.4+   |
|        |                  | Exposed sensitive    | Disclosure           | the cluster version  | k3s1       |
|        |                  | interfaces           |                      |                      |            |
| KHV005 | 10.43.0.1:443    | Discovery // Access  | Access to API using  | API reachable with   | APIVersio… |
|        |                  | the K8S API Server   | service account      | the pod service      |            |
|        |                  |                      | token                | account token        |            |
| None   | Local to Pod     | Credential Access // | Access to pod's      | Service-account      | …/service  |
|        |                  | Access container     | secrets              | files readable under | account/…  |
|        |                  | service account      |                      | /var/run/secrets/…   |            |
| KHV050 | Local to Pod     | Credential Access // | Read access to pod's | Token file contents  | eyJhbGci…  |
|        |                  | Access container     | service account      | readable in the pod  |            |
|        |                  | service account      | token                |                      |            |
+--------+------------------+----------------------+----------------------+----------------------+------------+

Compared with the remote scan, the pod vantage adds several rows:

ID / title What the pod vantage adds
CAP_NET_RAW enabled Raw-socket capability that can increase network attack options if a pod is compromised; actual impact depends on the CNI and network isolation
KHV043 / KHV036 Same kubelet health and anonymous-auth candidates seen from the interface scan (still validate KHV036 manually)
KHV002 K8s Version Disclosure /version returned v1.36.4+k3s1 via the in-cluster API service
KHV005 Access to API using service account token API reachability with a mounted token is normal for many pods; the real question is what RBAC permissions that token has
Access to pod secrets / KHV050 Token files under /var/run/secrets/kubernetes.io/… are readable; presence alone is not proof of a vulnerability

The presence of a service-account token is not by itself a Kubernetes vulnerability. Modern clusters often mount a projected token unless automountServiceAccountToken is disabled. The risk depends on whether the workload needs API access and on the service account’s RBAC permissions.

Compare the three vantage points on the same cluster:

  • Remote scan: saw API and kubelet ports, raised no vulnerability rows
  • Interface scan: raised kubelet health and anonymous-auth findings on 10.42.0.16:10250 (validate KHV036 manually)
  • Pod Job: repeated those kubelet findings and added service-account token reachability, version disclosure, and default capabilities

Delete the completed Job when you no longer need its logs: kubectl delete job kube-hunter.


Understand active hunting before enabling it

Passive hunting (default) discovers and probes without intending to change cluster state.

Active hunting (--active) may:

  • exec into containers via the kubelet
  • read container or host logs
  • attempt etcd writes
  • prove host-path abuse such as /var/log

Official docs warn that active hunting can be harmful. Rules for this guide:

  • Always list active hunters first: kube-hunter --list --active
  • Run passive remote / interface / pod scans first
  • Enable --active only with written authorization
  • Prefer a disposable lab cluster for active mode
  • Never make --active the first command in a tutorial copy-paste

This article does not run active hunting against the lab. The risk section is intentional.


Export and save results

Machine-readable output helps evidence and retests:

bash
kube-hunter --remote "$API_HOST" --report json --log none > kube-hunter-remote.json

The redirect writes the file and prints nothing when logging is off. Open the JSON in your editor or feed it to your report tooling. Useful for:

  • storing evidence next to the vantage point and tool version
  • comparing before/after remediation
  • feeding automation without scraping ASCII tables

Other report types include plain and yaml. Dispatch defaults to stdout; HTTP dispatch exists for custom collectors.


Remediate and retest

Use categories rather than memorizing every VID:

Finding type What to review Retest
Externally exposed management endpoint Firewall, LB rules, bind address Same --remote target
Unauthenticated / anonymous kubelet behavior Kubelet auth flags, who can reach 10250 (manual HTTP check) --interface or --pod
Overly reachable in-cluster service Service type, NetworkPolicy, RBAC --pod Job
Default capabilities / token exposure Pod security standards, automount token, RBAC, seccomp --pod after the PodSpec change
Version or health information leaks Whether the endpoint must be reachable from that network at all Matching vantage after change

After each fix, rerun the same kube-hunter command from the same vantage. Changing both the fix and the vantage makes results hard to compare.


kube-hunter vs kube-bench vs Trivy

Need Prefer
Attack-surface probing from a chosen location kube-hunter
CIS Benchmark on nodes / control plane kube-bench
Image CVE scanning Trivy or Grype
Manifest / IaC misconfig Trivy config or a dedicated manifest scanner
Ongoing Kubernetes posture / KBOM Trivy (current Aqua recommendation)

For PenTest+ study order: learn when each scanner type fits under vulnerability scanning concepts, practice container SCA with Trivy/Grype, then use kube-hunter when the engagement includes a Kubernetes attack surface. Follow Domain 3 and 4e on the CompTIA PenTest+ course hub.

For CKS-oriented study, kube-hunter can help demonstrate attacker vantage and exposed Kubernetes services, while kube-bench and Trivy cover more current audit and scanning workflows.


Troubleshooting

Symptom Likely cause Fix
kube-hunter finds nothing Vantage cannot reach weak services, or hunters have no match Try --interface or --pod; do not assume “safe”
Remote vs internal results disagree Expected: different network paths and credentials Record vantage with every report
Job image pull fails Registry or tag unavailable Pin aquasec/kube-hunter:0.6.8 or build from source
Active hunting scares the team Correct instinct Stay passive until authorized; use a lab for --active
Coverage appears outdated / no recent updates Project is not under active development Keep using it for vantage teaching; prefer Trivy for ongoing scanning
KHV036 without a confirmed anonymous success Known possible false positive Manually verify with unauthenticated curl before reporting

Summary

kube-hunter shows Kubernetes attack surface from a chosen place on the network. On this lab, a passive remote scan only listed the API and kubelet services, while --interface and an in-cluster Job raised kubelet health disclosure on 10.42.0.16:10250, anonymous-auth candidates, in-cluster API reachability with a service account token, and default pod capability notes.

Treat empty remote reports as incomplete evidence, not a clean bill of health. Manually verify findings such as KHV036 before you write them up. Keep active hunting off by default. Export JSON when you need a before-and-after trail.

Pair kube-hunter with kube-bench and Trivy so attack-surface probing, CIS audits, and image or config scanning each own their job. For PenTest+ prep, practice reading findings by vantage point first, then document remediation recommendations the same way you would for any Domain 3 finding.


References


Frequently Asked Questions

kube-hunter finds nothing — is the cluster safe?

No. An empty report only means no hunter raised a finding from that vantage with those options. Change vantage (--interface, --pod), confirm the target IP, and still run CIS and image scans.

What is the difference between remote and internal kube-hunter scans?

Remote mimics an outsider who knows an address. Interface, CIDR, and pod modes see host-visible networks, a subnet, or cluster-internal paths and, in pod mode, a service account token. Internal scans often find more.

Is active hunting destructive?

It can change cluster state. Official docs warn that active hunts may exec into containers or write to etcd. Use only with authorization, preferably on a disposable lab.

kube-hunter vs kube-bench — which should I run?

Use kube-hunter for attack-surface discovery from a vantage point. Use kube-bench for CIS Benchmark configuration checks on nodes and the control plane. They answer different questions.

Does kube-hunter scan container images?

No. It probes Kubernetes services and related weaknesses. Use Trivy or another image scanner for CVE inventory in images.

Can I run kube-hunter as a pod?

Yes. The upstream Job runs kube-hunter --pod inside the cluster to mimic a compromised workload. Delete the completed Job when you no longer need its logs.

Does kube-hunter need Kubernetes credentials?

Remote passive hunting is designed to work without admin credentials. Pod mode uses the mounted service account token. You can also pass --service-account-token when you want to impersonate a specific account.

Is every KHV036 finding a confirmed vulnerability?

No. kube-hunter 0.6.8 has a known possible false positive for KHV036. Confirm with an unauthenticated request to a sensitive kubelet path; 401 or 403 means anonymous access is not authorized.

Finished reading?Beta Get the key takeaways in seconds, then ask follow-up questions
Deepak Prasad

R&D Engineer

Founder of GoLinuxCloud with 15+ years of expertise in Linux, Python, Go, Laravel, DevOps, Kubernetes, Git, Shell scripting, OpenShift, AWS, Networking, and Security. With extensive experience, he excels across development, DevOps, networking, and security, delivering robust and efficient solutions for diverse projects.

  • Go (programming language)
  • Python (programming language)
  • DevOps
  • Computer Security
  • Cloud Computing
  • Kubernetes
  • Linux
  • Ansible (software)