A flaw was found in insights-client. When the application receives a non-200 response, it logs the request headers, which can include the cloud.openshift.com pull-secret token. A local user with access to pod logs on the hub could read this long-lived credential. This information disclosure could grant unauthorized access to Red Hat cloud services.
A flaw was found in insights-client. The component's ServiceAccount is bound to a ClusterRole granting cluster-wide secrets get, list, and watch permissions, while the code only requires access to a single specific Secret. This excessive privilege means that a compromise of the insights-client pod or ServiceAccount token would grant an attacker read access to all Secrets across the hub cluster, including managed-cluster kubeconfigs and other sensitive credentials.
The setDefault() function in pkg/config/config.go logs every environment variable it consumes via glog.V(2).Infof("Using %s from environment: %s", env, val), including CCXTOKEN — a bearer credential used by disconnected clusters as an alternative to cloud.redhat.com (which is unreachable from their environments). At -v>=2 verbosity, the token is printed in clear text to the pod log on every startup. The credential is then accessible to any principal with pods/log access in the open-cluster-management namespace or access to centralized logging (Loki/Elasticsearch), crossing a privilege boundary since log readers typically do not have secrets access to the credential source.
Code path: main.go:36 SetupConfig() → pkg/config/config.go:46 setDefault(&Cfg.CCXToken, "CCXTOKEN", "") → config.go:62 glog.V(2).Infof("Using %s from environment: %s", env, val).
Preconditions: (1) Operator has set -v>=2 on the insights-client Deployment (non-default but routinely enabled for debugging); (2) CCXTOKEN environment variable is configured (disconnected cluster deployments).
Upstream: stolostron/insights-client
ClusterID is read from ManagedCluster.Status.ClusterClaims["id.openshift.io"] (fallback id.k8s.io). ClusterClaims are set by the registration/work agent on the managed (spoke) cluster and synced verbatim into the hub ManagedCluster.status -- they are spoke-controlled data crossing a trust boundary. The value is concatenated raw into the request path: http.NewRequest("GET", endpoint+"/cluster/"+cluster.ClusterID+"/reports", nil), with the hub's pull-secret bearer token attached. No UUID validation or URL encoding is applied. A compromised spoke can inject path traversal sequences or redirect the authenticated request to unintended API endpoints.
Upstream: stolostron/insights-client
CreateInsightsRequest sets the Authorization header to "Bearer " + the cloud.openshift.com pull-secret token. In CallInsights, when the response status is not 200, the function logs the request headers at verbosity >= 3 via glog.V(3).Infof("Response header for report %v", req.Header), which writes the cluster's long-lived cloud.openshift.com pull-secret credential to stderr / pod logs. Pod logs on the hub are readable by any principal with pods/log access. The pull-secret is a long-lived credential that grants access to Red Hat cloud services.
Upstream: stolostron/insights-client
The insights-client ServiceAccount is bound to a ClusterRole granting cluster-wide secrets get/list/watch. The code only requires access to a single Secret — openshift-config/pull-secret (pkg/retriever/reportretriever.go:111-112, StartTokenRefresh). The over-broad RBAC means a compromise of the insights-client pod or ServiceAccount token grants read access to every Secret on the hub cluster, including managed-cluster kubeconfigs, ArgoCD/GitOps credentials, and other addon tokens. This significantly amplifies the impact of any code execution or credential theft vulnerability in insights-client (e.g., CVE-2026-71474, CVE-2026-71845).
The production ClusterRole should be scoped to the minimum required: get on the specific Secret openshift-config/pull-secret in the openshift-config namespace, rather than cluster-wide secrets access.
Upstream: stolostron/insights-client