fix(kubernetes-client-api): NO_PROXY hostname boundary matching - #7950
Open
GrosQuildu wants to merge 2 commits into
Open
fix(kubernetes-client-api): NO_PROXY hostname boundary matching#7950GrosQuildu wants to merge 2 commits into
GrosQuildu wants to merge 2 commits into
Conversation
GrosQuildu
marked this pull request as ready for review
June 26, 2026 13:54
GrosQuildu
requested review from
ash-thakur-rh,
manusa and
shawkins
as code owners
June 26, 2026 13:54
GrosQuildu
added a commit
to GrosQuildu/kubernetes-client
that referenced
this pull request
Jun 26, 2026
GrosQuildu
force-pushed
the
ptp-75-no-proxy-boundary-pr
branch
from
June 26, 2026 17:14
ab413a1 to
2cf4773
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Description
Fabric8 uses the configured
NO_PROXYlist to decide whether Kubernetes API traffic should bypass the configured proxy. When the Kubernetes API host matches oneNO_PROXYentry,HttpClientUtils.configureProxyforces the transport builder to useDIRECTproxy mode.However,
isHostMatchedByNoProxytreats each non-IPNO_PROXYentry as a raw string suffix. A configuration that excludescorp.examplefrom proxying also excludesevilcorp.example, even thoughevilcorp.exampleis neither the exact hostcorp.examplenor a DNS-label subdomain of it.The issue affects all HTTP transports that use
HttpClientUtils.applyCommonConfiguration, because the proxy decision happens before the backend-specific builder is returned.Exploit Scenario
An operator service accepts tenant-supplied cluster registrations but requires all non-corporate Kubernetes API traffic to traverse an internal proxy. The service sets
HTTPS_PROXY=http://proxy.internal:8080andNO_PROXY=corp.example, intending to bypass the proxy only forcorp.exampleand its subdomains. An attacker registers a cluster athttps://evilcorp.example. Fabric8 compares the host tocorp.examplewithendsWith, marks the request as direct, and sends Kubernetes client traffic outside the proxy path. The attacker bypasses the egress proxy's allowlist and audit controls, and, if the attacker-controlled endpoint is trusted by the client configuration, can receive credential-bearing Kubernetes API requests.The following Java regression test can be added to
kubernetes-client-api/src/test/java/io/fabric8/kubernetes/client/utils/HttpClientUtilsTest.java. It uses the realConfigBuilderpath and the real proxy configuration helper. The test fails on the vulnerable implementation because Fabric8 callsproxyType(DIRECT)instead of configuringproxy.internal:8080.Java PoC demonstrating that
NO_PROXY=corp.example.must not matchevilcorp.example..Verification command:
./mvnw -B -ntp -pl kubernetes-client-api \ -Dsurefire.failIfNoSpecifiedTests=false \ -Dtest=HttpClientUtilsTest testThe vulnerable matcher can also be observed directly with the compiled
kubernetes-client-apijar:JShell proof using the compiled Fabric8 class.
Observed vulnerable output:
The first line is the issue. After the patch,
evilcorp.examplereturnsfalse, while the exact host and subdomain cases still returntrue.NO_PROXY Behavior Comparison
Fabric8 documents
NO_PROXYas GNU Wget-style proxy configuration, and the maintainer feedback points to the GNU Wget manual as the expected behavior. The key compatibility point is that a hostname entry is not a raw string suffix:corp.examplemay matchcorp.exampleandapi.corp.example, but should not matchevilcorp.example.NO_PROXYentryurllibhttpproxy/ client-gocorp.examplecorp.examplecorp.exampleapi.corp.examplecorp.exampleevilcorp.example.corp.examplecorp.example.corp.exampleapi.corp.exampleThe vulnerability is the third row. Current Fabric8 treats
evilcorp.exampleas covered bycorp.example, while GNU Wget, curl, Python, Go, and Kubernetes client-go do not.There is one compatibility nuance for leading-dot entries. The patch below strips a leading dot from hostname entries, so it follows curl/Python behavior for
.corp.example: the entry matches both the exact host and subdomains. GNU Wget and Go treat a leading-dot entry as subdomain-only. If maintainers want strict GNU Wget/Go behavior, preserve aleadingDotflag and make.corp.examplematchapi.corp.examplebut notcorp.example. That policy choice is separate from the security fix; both variants must rejectevilcorp.exampleforNO_PROXY=corp.example.References:
httpproxyNO_PROXYdocumentation: https://pkg.go.dev/golang.org/x/net/http/httpproxy#Confighttp.ProxyFromEnvironmentby default when no explicit proxy function is configured.Threat Model
This seems like just a technical bug.
Deduplication
Adjacent public items exist, but they do not fix this issue:
*.domain.com.NO_PROXYentries.containstoendsWith, but did not add a DNS-label boundary check.NO_PROXYas the common direct-transport decision point.Fix
Require hostname
NO_PROXYentries to match either the exact normalized host or a dot-delimited subdomain. Preserve IP and CIDR behavior, normalize case, and strip one trailing DNS root dot from both sides so fully qualifiedexample.com.notation continues to work. The patch below also strips a leading dot from hostname entries, which follows curl/Python behavior; for strict GNU Wget/Go behavior, keep a leading-dot flag and make leading-dot entries match subdomains only.Paweł Płatek from Trail of Bits in collaboration with OpenAI.