
No flags are included in this writeup.
Overview
Split Horizon placed me inside a Kubernetes lab through a restricted bastion account. The service account had very limited permissions: it could view node-level metadata, but it could not list pods, list services, or proxy freely through kubelet/API server paths.
At first this looked like a dead end. The key idea was that node metadata still leaked enough networking information to understand how the cluster routed traffic internally.
The final solve required using Kubernetes DNS and the node overlay network to discover and reach an internal pod that was not visible through the API.
| Field | Value |
|---|---|
| Month | April 2026 |
| Points | 30 |
| Main area | Kubernetes networking, flannel VXLAN, CoreDNS |
Initial Enumeration
I started by checking what the bastion account was allowed to access:
kubectl auth can-i --list
The important permission was:
nodes get/list
Direct approaches such as node proxying and kubelet access were blocked. That confirmed the intended route was not “just use the Kubernetes API harder.”
The next step was inspecting the nodes:
kubectl get nodes -o json
This revealed useful networking metadata:
- Pod CIDRs assigned to each node
- Cluster service CIDR
- Cluster DNS IP
- flannel VXLAN backend details
- node internal IPs
- flannel VTEP information
That was the turning point. The account could not see workloads, but it could still see enough of the network map.
Reconstructing The Network Path
The cluster used flannel with VXLAN. Since the node metadata exposed the relevant flannel configuration, I recreated a compatible VXLAN interface on the bastion and added routes for the pod and service CIDRs.
This allowed the bastion to send traffic into the Kubernetes overlay network even though it was not itself a Kubernetes workload.
After setting up the route, CoreDNS became reachable:
dig @10.43.0.10 kubernetes.default.svc.cluster.local
That confirmed the bastion could now communicate with the internal Kubernetes service network.
Using DNS As The Service Oracle
The API did not allow service listing, but CoreDNS could still answer DNS queries.
The useful trick was reverse DNS lookup across the service CIDR:
dig @<cluster-dns> -x <cluster-ip>
By scanning the service CIDR, I could discover internal service names that were hidden from the Kubernetes API permissions.
Once the interesting service name appeared, the rest was network routing and careful probing. The solve path was no longer about Kubernetes object permissions. It was about reaching the workload directly through the reconstructed overlay path.
Root Cause
The challenge demonstrates that “node-only” Kubernetes visibility is not necessarily blind.
Even without access to Pods or Services, node metadata can expose:
- Pod CIDR assignments
- overlay network configuration
- service CIDR
- cluster DNS location
- node routing details
With that information, it is possible to reconstruct enough of the network path to query internal DNS and reach workloads directly.
The core issue is that Kubernetes networking metadata can become an unintended discovery and access primitive when combined with network-level access from a bastion.
Takeaways
My biggest notes:
- Kubernetes API restrictions do not always prevent network-level discovery
- CoreDNS can reveal service names even when the API blocks service listing
- reverse DNS over ClusterIPs can expose hidden internal endpoints
- node metadata can leak enough overlay-network details to reconstruct pod/service routing
- direct network reach and Kubernetes object permissions are different security boundaries
Split Horizon is currently the hardest challenge by public solve count in this run. The final flag name fit the solution perfectly: packets had to take the scenic route.