Your Kubernetes config says that service is internal. Your cluster may disagree. Shopify hit this exact problem at scale, built a scanner to resolve the argument, and published the result on October 19. Overexposed queries what GKE and Cloud Run are actually enforcing — not what your repository claims — then probes each endpoint from the outside, the way an attacker would.
The Gap Between Intent and Enforcement
Most teams assume their Terraform or YAML files describe what’s live. They don’t — not reliably. Shopify learned this when their first attempt at exposure scanning read directly from repository config files and produced two problems simultaneously: false positives on services that were actually protected, and blind spots on services that were genuinely exposed.
Three failure modes drove the rebuild:
- Admission controllers. They rewrite resource settings at admission time. What lands in your cluster can differ meaningfully from what you committed.
- Platform tooling. Ingresses created by internal platform systems or other teams’ repositories are invisible to a scanner that only reads your repo.
- Annotation drift. Proxy authentication annotations applied directly to resources don’t always show up in version control.
The team’s framing is worth keeping: “A repository shows what a team wanted, not what the cluster actually runs.” That distinction matters operationally.
How Overexposed Works
The rebuilt scanner skips config files entirely. Instead, it queries GCP Cloud Asset Inventory — which returns resources in their post-admission-controller state — then probes each discovered endpoint anonymously:
from google.cloud import asset_v1
request = asset_v1.SearchAllResourcesRequest(
scope=scope,
asset_types=["networking.k8s.io/Ingress", "run.googleapis.com/Service"],
read_mask=FieldMask(paths=["*"]),
page_size=500,
)
Each probe starts with an HTTP HEAD request (falling back to GET if rejected) and follows up to three redirects. The scanner also tests case-sensitive path variations like /ADMIN, since routing rules can be case-sensitive — a known bypass vector.
Every endpoint receives one of six verdicts:
- Exposed — unauthenticated access worked; no allowlist approval on record
- Expected — public by design and approved in an in-code allowlist
- Protected — authentication or access controls blocked the probe
- Not Found — proxy answered, but the path doesn’t exist
- Unreachable — connection failed
- Inconclusive — evidence received but insufficient to classify
That last verdict deserves emphasis. Inconclusive does not mean protected. A 403 response doesn’t prove protection without context. The scanner reports uncertainty rather than assuming safety — and that conservative stance is the right call.
Status codes also carry context-specific meaning here. A 404 behind a GKE Ingress means the proxy answered and the path doesn’t exist. The same 404 on Cloud Run might come from Google’s front end before your application ran at all. Overexposed handles both cases separately.
The Scanner Itself Is an Attack Surface
Because Overexposed makes outbound HTTP requests to arbitrary hostnames, it carries inherent SSRF risk. The team addressed this with four layers: DNS validation that rejects loopback and RFC1918 addresses, direct IP connections that prevent DNS rebinding, repeated SSRF checks on each redirect hop, and restricted network egress from the scanner instance to block access to cloud metadata endpoints like 169.254.169.254.
The recommendation is to apply that last control at the infrastructure level too, not just in code. A security tool that can be turned into an internal pivot point is worse than no tool at all.
Why Your Cluster Needs This Now
The scale of the problem is not theoretical. Google’s own data from 2025 found that 54% of GKE clusters had an internet-exposed API server. Threat actors were exploiting misconfigured GCP and GKE instances in under an hour of creation. Wiz researchers found over 6,500 clusters — including Fortune 500 companies — publicly exposing vulnerable ingress controller admission controllers. CVE-2026-4342 in Ingress-Nginx (CVSS 8.8) enables code execution in the controller and, because default installs grant cluster-wide access, can expose every Secret in the cluster.
Overexposed’s design directly addresses how these exposures happen: not through known vulnerabilities in most cases, but through configuration drift that no one noticed.
Limitations and Next Steps
The tool is scoped to Google Cloud — GKE Ingresses and Cloud Run services only. Teams running EKS or AKS would need to build an equivalent using AWS Config or Azure Resource Graph. The principle is the same; the implementation is theirs to write.
Shopify published a reference implementation as a starting point alongside the full engineering writeup, including probe logic and SSRF hardening details, on the Shopify Engineering Blog. InfoQ’s technical breakdown covers additional implementation detail worth reading alongside it.
If you’re running on GKE or Cloud Run, run this against your cluster before assuming your config describes reality. The gap between the two is where incidents happen.













