Skip to content

fix(httpclient): apply proxy settings to Jetty and Vertx-5 WebSocket clients - #7949

Open
GrosQuildu wants to merge 3 commits into
fabric8io:mainfrom
GrosQuildu:ptp-66-websocket-proxy-settings
Open

fix(httpclient): apply proxy settings to Jetty and Vertx-5 WebSocket clients#7949
GrosQuildu wants to merge 3 commits into
fabric8io:mainfrom
GrosQuildu:ptp-66-websocket-proxy-settings

Conversation

@GrosQuildu

@GrosQuildu GrosQuildu commented Jun 26, 2026

Copy link
Copy Markdown
Contributor

Description

Fabric8 applies configured proxy settings to the ordinary HTTP clients in the Jetty and Vert.x 5 transport modules, but both modules create separate WebSocket clients and left those WebSocket clients without the same proxy configuration.

In httpclient-jetty, JettyHttpClientBuilder.build() creates sharedHttpClient and a separate WebSocketClient backed by its own Jetty HttpClient. The proxy switch added HttpProxy, Socks4Proxy, or Socks5Proxy only to sharedHttpClient.getProxyConfiguration(). The backing sharedWebSocketClient.getHttpClient() remained direct.

In httpclient-vertx-5, Vertx5HttpClientBuilder.build() called applyProxy(httpOptions) for WebClientOptions, then created independent WebSocketClientOptions without applying proxy options to them.

Fabric8 uses WebSockets for credential-bearing Kubernetes operations including pod exec, attach, port-forward, upload/copy paths that run over exec, and WebSocket watches. As a result, a caller can configure a proxy expecting all Kubernetes API traffic to traverse an approved egress route or audit point, but WebSocket-backed operations with these two transports connect directly to the API server when direct network access is available.

The other production HTTP transports do not have this split-client omission. The JDK transport configures the proxy on java.net.http.HttpClient and creates WebSockets with getHttpClient().newWebSocketBuilder(). The OkHttp transport configures the proxy on the shared OkHttpClient and creates WebSockets with that same client. The Vert.x 4 transport sets proxy options on the single Vert.x HttpClient and opens WebSockets through that client. The vulnerable pattern is specific to Jetty and Vert.x 5 because they build separate WebSocket client objects whose proxy options were not populated.

Exploit Scenario

An organization requires Kubernetes API traffic from controller processes to pass through an internal proxy for network allowlisting and audit logging. A controller built with Fabric8 uses the Jetty or Vert.x 5 HTTP client and sets an HTTP proxy through the normal client configuration.

Regular resource CRUD requests honor the proxy. Later, the controller performs pod.exec, attach, portForward, or a WebSocket watch. Those WebSocket upgrade requests are built from separate WebSocket clients whose proxy settings were never populated, so the process opens a direct connection to the Kubernetes API server with the same credentials and bypasses the organization's proxy policy.

Threat Model

This is just a regular bug.

Fix

Apply the selected proxy type, address, and proxy authentication to Jetty's WebSocket backing HttpClient and to Vert.x 5 WebSocketClientOptions.

Keep the existing Jetty and Vert.x 5 builder/configuration tests, and add the shared AbstractHttpClientWebSocketProxyTest subclasses so all production HTTP clients must continue to route WebSocket tunnel setup through the configured HTTP proxy.

The shared test starts a mock HTTP proxy and configures the client under test to use it. It then opens a WebSocket through client.newWebSocketBuilder() to an https://127.0.0.1:<unused-port>/proxied-websocket target. The target port is closed, so the only successful observable route is the configured proxy. The test passes only when the mock proxy receives the expected CONNECT 127.0.0.1:<unused-port> tunnel request. Vulnerable WebSocket clients connect directly to the closed loopback port, so the mock proxy sees no CONNECT and the test times out.

Negative validation on current main with the new behavioral test added:

./mvnw -B -ntp -pl httpclient-jetty -am -DskipITs \
  -Dsurefire.failIfNoSpecifiedTests=false \
  -Dtest=JettyHttpClientWebSocketProxyTest test

Result:

JettyHttpClientWebSocketProxyTest.proxiedWebSocketUsesConfiguredHttpProxy
ConditionTimeoutException: AtomicReference[null] did not receive CONNECT within 10 seconds.
BUILD FAILURE
./mvnw -B -ntp -pl httpclient-vertx-5 -am -DskipITs \
  -Dsurefire.failIfNoSpecifiedTests=false \
  -Dtest=Vertx5HttpClientWebSocketProxyTest test

Result:

Vertx5HttpClientWebSocketProxyTest.proxiedWebSocketUsesConfiguredHttpProxy
ConditionTimeoutException: AtomicReference[null] did not receive CONNECT within 10 seconds.
BUILD FAILURE

Positive validation on the patched PR branch:

./mvnw -B -ntp \
  -pl httpclient-jdk,httpclient-okhttp,httpclient-vertx,httpclient-vertx-5,httpclient-jetty \
  -am -DskipITs -Dsurefire.failIfNoSpecifiedTests=false \
  -Dtest='*WebSocketProxyTest' test

Result:

JdkHttpClientWebSocketProxyTest:    Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
JettyHttpClientWebSocketProxyTest:  Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
OkHttpClientWebSocketProxyTest:     Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
VertxHttpClientWebSocketProxyTest:  Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
Vertx5HttpClientWebSocketProxyTest: Tests run: 1, Failures: 0, Errors: 0, Skipped: 0
BUILD SUCCESS

Paweł Płatek from Trail of Bits in collaboration with OpenAI.

@GrosQuildu GrosQuildu changed the title Apply proxy settings to WebSocket clients fix(httpclient): apply proxy settings to Jetty and Vertx-5 WebSocket clients Jun 26, 2026
GrosQuildu added a commit to GrosQuildu/kubernetes-client that referenced this pull request Jun 26, 2026
Add a shared behavioral test that opens a WebSocket with an HTTP proxy
configured and asserts the proxy receives the CONNECT tunnel request. Wire the
shared test into the JDK, OkHttp, Vert.x 4, Vert.x 5, and Jetty client modules.
@GrosQuildu
GrosQuildu force-pushed the ptp-66-websocket-proxy-settings branch from 7f0eeb4 to d1d110f Compare June 26, 2026 17:14
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant