CVE-2026-117681: Konflux-ci: ui proxy skips backend tls verification on non-openshift clusters, leaking a token that can impersonate anyone

Published Oct 28, 2026
·
Updated

A flaw was found in konflux-ci. This vulnerability allows privilege escalation when the user interface proxy automatically disables Transport Layer Security (TLS) certificate verification for connections to internal backend services in environments lacking a default service certificate authority. Because the proxy attaches a cluster-scoped authentication token with user impersonation rights to these requests, an adjacent network attacker capable of intercepting traffic can capture the credentials to gain full administrative control of the cluster.

Other sources

Description The konflux-ui proxy sends its ServiceAccount token to the Tekton Results, Kite and KubeArchive backends with TLS verification turned off. That token can impersonate any user or group, so anyone who can get in the middle of thosecalls ends up with cluster-admin.

Where it happens The proxy init container script, generate-proxy-config.sh, does this at lines 99-107. The same code ships inside the operator's generated UI manifests, lines 332-340. The script writes the shared TLS transport config like this:

if [ -f "${SERVICECAPATH}" ]; then ... tlstrustpool file ... else ... tlsinsecureskipverify ... fi That path points at the OpenShift service CA, which reaches the pod through a ConfigMap mounted as optional in proxy.yaml. Only the OpenShift service-ca operator creates that ConfigMap, and nothing in this repo does. I checked trust-manager too, since it was the most likely candidate to populate it, but its Bundle is named trusted-ca and writes a different key. So on Kind, plain Kubernetes, EKS, GKE and the rest, the file is never present and the else branch always runs.

Three Caddy snippets import that config: the ones for Tekton Results, Kite and KubeArchive. All three also attach the proxy's own ServiceAccount token:

headerup Authorization "Bearer {http.vars.kubetoken}" That token is projected in proxy.yaml, lines 199-205, with no audience set, so the Kube API accepts it directly. And rbac.yaml grants the ServiceAccount:

- apiGroups: [""] resources: ["users", "groups"] verbs: ["impersonate"] cluster-wide, with no resourceNames. Holding that token is therefore as good as holding cluster-admin:

kubectl --token=<token> --as=anyone --as-group=system:masters get secrets -A Worth noting the manifest already has the right idea next door. A second volume, lines 210-217, projects a token scoped to the konflux-backend audience, exactly to limit blast radius. These three routes simply do not use it, and there is a TODO in the Tekton Results snippet saying so.

Why it matters Every UI request to the Tekton Results plugin path opens a TLS connection to a DNS name, checks neither the certificate nor the hostname, and hands over that token. Any pod that can answer for that name, or sit in the path, gets cluster-admin. From there you can read the Tekton Chains signing key and sign images and provenance that pass the default EnterpriseContractPolicy.

This affects every non-OpenShift install, including the Kind quickstart and the local deploy script. The operator is affected too, since it ships the same script and sets the Results hostname and the Kite and KubeArchive toggles from the KonfluxUI CR.

It is easy to miss because nothing breaks. The downgrade appears only as a single line in the init container log, saying no service CA was found and verification is disabled. The generated config lives on an emptyDir, so the phrase tlsinsecureskipverify appears nowhere in the committed YAML or in kustomize output. OpenShift CI always takes the secure branch. Kind CI takes the insecure one and passes, because skipping verification never fails a connection.

Why the cluster CA is not the answer My first instinct was that the pod already mounts a CA that would do the job, since the cluster-ca volume carries the konflux-issuer root and the Caddyfile already uses it on line 90. That works for namespace-lister, which really is issued by konflux-issuer.

Tekton Results is not. The Tekton Operator deploys it with a self-signed certificate outside the Konflux PKI, and there is no Certificate for it anywhere in this repo. The trust-manager bundle carries only public CAs plus the konflux-ca root, so it does not help either. segment-bridge hits the same wall and works around it with an OpenShift-only CA injection annotation, on a volume that is likewise optional.

So konflux-issuer is not the anchor for these backends, and pointing the transport config at it would break the Tekton Results route rather than fix it. That does not mean no anchor exists. The certificate Tekton Results already serves turns out to work, which is what the next section is about.

What I would suggest I built a throwaway Kind cluster, installed the Tekton Operator at the version this repo pins, v0.81.1, with the TektonConfig from this repo, and checked what Tekton Results actually serves. The cluster is deleted now.

Its certificate looks like this:

subject = CN = tekton-results-api-service.tekton-pipelines.svc.cluster.local issuer = CN = tekton-results-api-service.tekton-pipelines.svc.cluster.local X509v3 Subject Alternative Name: DNS:tekton-results-api-service.tekton-pipelines.svc.cluster.local X509v3 Basic Constraints: critical CA:FALSE Two things follow, and I checked both rather than assuming.

First, the SAN is exactly the hostname the init container probes and dials, so hostname verification passes as-is and nothing needs reissuing.

Second, it is self-signed and marked as not a CA. Go still accepts a self-signed leaf as its own trust anchor when it sits in the root pool, which is what Caddy builds from a trust pool file. I confirmed that against the running service:

today (insecure skip) HANDSHAKE OK fix (trust pool = tr.crt) HANDSHAKE OK <-- the fix works control (system roots) HANDSHAKE FAILED: certificate signed by unknown authority The control case matters. It shows the certificate genuinely is not publicly trusted, so verification is doing real work rather than passing by accident.

So this is fixable entirely inside konflux-ci, with no upstream dependency and without reissuing anything:

The operator reads the Tekton Results TLS secret from the Tekton namespace. It republishes that certificate into a ConfigMap in the konflux-ui namespace. That ConfigMap is mounted into the proxy init container. A new environment variable points the script at it, and the proxy verifies instead of skipping. The same shape works for Kite and KubeArchive with their own serving certs. Rotation needs handling, since the certificate I saw is valid for a year and the Tekton Operator owns it. Watching that Secret and rolling the proxy on change covers it.

Two smaller things worth doing regardless:

Bound the group impersonation grant in rbac.yaml. It currently allows groups with no resourceNames, and that is what turns a leaked token into unconditional cluster-admin. Users cannot be enumerated, but groups usually can, and that alone drops the ceiling from cluster-admin to whatever the impersonated user actually has. Make the insecure path opt-in and logged rather than silently chosen, so a non-OpenShift install is auditable instead of looking identical to a verified one. I have both pieces written locally and not pushed anywhere public:

The init container change, which adds the CA path variable, makes the insecure path opt-in behind its own flag, and logs it instead of choosing it silently. Output is byte-identical to today on both OpenShift and non-OpenShift, so on its own it changes no behaviour. The operator change, which reads the Tekton Results secret, validates that it parses as a certificate, republishes it as a content-hashed ConfigMap, mounts it, and sets the path variable. It watches that Secret so a rotation republishes and rolls the proxy, and it applies before the manifests and prunes after, so a superseded revision is never deleted while the Deployment still mounts it. Unit tests and the envtest suite pass, and the upstream manifests stay in sync. What I have not done is exercise it end to end on a full Konflux install, so treat it as a proposal rather than something ready to merge. Happy to send it wherever suits, or to rework it if you would rather bring Tekton Results into the Konflux PKI than couple the UI operator to its Secret. That is an architectural call I did not want to make on your behalf.

Other details Found by reading the code on commit 1fc51a8, on main.

— Red Hat

Affected Software

0 affected components

Event History

Oct 28, 2026
Data Sourced
via Red Hat·10:30 PM
DescriptionSeverityAffected Software
Oct 31, 2026
CVE Published
via MITRE·08:57 AM
Data Sourced
via MITRE·08:57 AM
DescriptionSeverityWeakness
Data Sourced
via NVD·09:16 AM
DescriptionSeverityWeakness

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203