Skip to the content.

KSail: the local web UI checked Host only on writes, so a rebinding page could read cluster Secrets

Advisory: GHSA-g57x-rm7r-hf26 (published 2026-10-17) Package: github.com/devantler-tech/ksail/v7 (Go), affected < 7.203.23, patched in 7.203.23 Weakness: CWE-346, CWE-200, CVSS 3.1 AV:N/AC:H/PR:N/UI:R/S:U/C:H/I:N/A:N (Medium, 5.3)

KSail is a CLI for creating and running local Kubernetes clusters. ksail open web starts a web UI on a random loopback port. The API behind it has no session or token in local mode, and the code treats the 127.0.0.1 binding as the security boundary.

Root cause

The API had an originGuard middleware in pkg/webui/api/server.go, written to protect the unauthenticated loopback UI from DNS rebinding. It compared Host and Origin with the listener’s origin, but only for mutating methods:

if !isMutating(request.Method) || s.UIOrigin == "" {
    next.ServeHTTP(writer, request)
    return
}

Writes were covered. Reads were not, and some reads are sensitive. GET /api/v1/clusters/{namespace}/{name}/proxy/{path...} forwards a read to the cluster’s kube-apiserver using the TLS client config and bearer token from the user’s kubeconfig (pkg/webui/api/kubeproxy.go, pkg/cli/clusterapi/kubeproxy.go). The .../watch/{path...} stream had the same exposure, and GET /api/v1/clusters returned the cluster names a caller needs to build the proxy URL.

A page that rebinds its own hostname to 127.0.0.1 is same-origin from the browser’s point of view, so it can read the responses. Its requests still carry the attacker’s hostname in Host, which is why a Host check on every method is enough to stop it.

The desktop app was not affected, because it hands the handler to the Wails webview and binds no TCP listener.

Fix

Pull request #7850 (“check Host and Origin on every local web UI request”, commit a975a82) makes originGuard apply to every request when a UI origin is configured. Host must address the listener origin, and Origin, when present, must match it. Clients that send no Origin still work. The desktop webview and the in-cluster operator, which have no UI origin, are unchanged.

The new tests in pkg/webui/api/origin_guard_test.go send a foreign Host to the proxy, watch, multiplexer, cluster list, settings and UI root, with and without Origin, and check that the request never reaches the cluster proxy. The pull request notes that these tests fail against the previous guard. The fix shipped in 7.203.23.

What I took from it

Thanks to the KSail maintainer for a quick fix with tests across all the affected routes, and for publishing the advisory.