Automated Threat Modeling

Overview of CVE-2026-94290: Rancher Fleet Import Controller Privilege Escalation to Cluster Admin on the Management Cluster

A brief summary of CVE-2026-94290, an authorization flaw in SUSE Rancher Fleet's agent management controller that lets an ordinary Rancher user gain cluster admin on the local management cluster. It covers the root cause, the two-layer patch, detection approaches and affected versions.

CVE Analysis

12 min read

Gaurav Sarraf
Gaurav Sarraf

2026-11-03

Overview of CVE-2026-94290: Rancher Fleet Import Controller Privilege Escalation to Cluster Admin on the Management Cluster
Experimental AI-Generated Content

This CVE analysis is an experimental publication that is completely AI-generated. The content may contain errors or inaccuracies and is subject to change as more information becomes available. We are continuously refining our process.

If you have feedback, questions, or notice any errors, please reach out to us.

[email protected]

Introduction

An ordinary Rancher user holding nothing more than the default user global role, with no role bindings on the management cluster, could obtain full cluster-admin on Rancher's local cluster simply by pointing a Fleet Cluster object at the wrong kubeconfig Secret. Because the management cluster holds the credentials and API tokens for every downstream cluster, the vendor advisory states that the impact of CVE-2026-94290 extends to every cluster managed by the installation.

Fleet is SUSE's Kubernetes deployment engine. Built from custom resource definitions and controllers, it manages GitOps deployments from Kubernetes YAML, Helm charts and Kustomize. It ships bundled with Rancher and is enabled by default. SUSE reports recognition as a Leader in The Forrester Wave for Multicloud Container Platforms, Q3 2025, and placement in the Leaders Quadrant of Gartner's 2025 Magic Quadrant for Container Management with SUSE Rancher Prime. These are vendor-reported analyst recognitions, not market share figures. Because Fleet's controllers run with administrative rights on the management cluster, their authorization decisions sit directly on the trust boundary between Rancher tenants and the platform itself.

Technical Information

The privileged controller

Fleet's agent management, or "import", controller runs on Rancher's management cluster, called local, with cluster administrator privileges. Fleet Cluster objects reference a kubeconfig Secret through spec.kubeConfigSecretNamespace, and the controller uses that Secret to install and manage a Fleet agent on the target cluster. Whatever credentials the Secret contains, the controller will use on behalf of whoever created the Cluster object.

That makes the question "which Secrets may this Cluster reference?" a security decision. In affected versions, the controller answered it incorrectly.

Root cause: a namespace name allowlist

The vulnerable code resolved spec.kubeConfigSecretNamespace through allowedKubeConfigSecretNamespace(). The following is reconstructed from the removed and context lines of the fix diff:

func allowedKubeConfigSecretNamespace(cluster *fleet.Cluster) (string, error) { if cluster.Spec.KubeConfigSecretNamespace == "" || cluster.Spec.KubeConfigSecretNamespace == cluster.Namespace { return cluster.Namespace, nil } ns := cluster.Spec.KubeConfigSecretNamespace if ns == "fleet-local" || ns == "fleet-default" || ns == config.DefaultNamespace || ns == config.LegacyDefaultNamespace || ns == fleetns.SystemRegistrationNamespace(config.DefaultNamespace) || ns == fleetns.SystemRegistrationNamespace(config.LegacyDefaultNamespace) || strings.HasPrefix(ns, "cluster-") { return ns, nil } return "", fmt.Errorf("kubeConfigSecretNamespace %q is not an allowed Fleet namespace", ns) }

The function checks only where the Secret lives, never who is asking for it. A Cluster created in any namespace, including a workspace owned by an ordinary user, could reference a Secret in any of the well-known namespaces and pass. The critical entry is fleet-local, which holds the kubeconfig for the management cluster itself. The PR description also notes that the cluster- prefix rule matched a namespace name that "any namespace could claim".

The result is a confused deputy. The controller supplies authority that the initiating user does not possess directly. NVD records CWE-250 (Execution with Unnecessary Privileges). The GitHub advisory also lists CWE-269 (Improper Privilege Management), CWE-441 (Unintended Proxy or Intermediary) and CWE-863 (Incorrect Authorization).

Attack flow

Based on the advisory and the patch description, the documented attack path looks like this:

  1. An authenticated Rancher user holds only the default user global role. No role bindings on local and no nondefault configuration are required. Fleet is enabled by default, and ordinary users' ability to create Fleet workspaces is intentional behavior.
  2. The user creates a Fleet workspace, which gives them a namespace they control.
  3. In that namespace, the user creates a Fleet Cluster whose spec.kubeConfigSecretNamespace names fleet-local, referencing the management cluster's own administrative kubeconfig (the local-cluster Secret used in the fix's end-to-end test).
  4. The import controller evaluates the reference with allowedKubeConfigSecretNamespace(). Because fleet-local is on the allowlist, the reference is accepted.
  5. The controller builds a client from those credentials and deploys a Fleet agent onto local, managing the management cluster on the user's behalf.
  6. Fleet content the user controls, such as bundles targeting their Cluster, is then applied to the management cluster with elevated privileges, which yields full cluster-admin.

From there the advisory documents access to all management cluster secrets (including downstream cluster credentials and API tokens), the ability to change RBAC and any other resource, and the ability to disrupt the Rancher management server.

Severity scoring

  • SUSE CNA, CVSS 3.1: 9.1 Critical, CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:H/A:H
  • GitHub advisory, CVSS 4.0: 9.4 Critical, CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:H/VI:H/VA:H/SC:H/SI:H/SA:H
  • NIST: no separate NVD assessment in the retrieved record

The two scores come from different scoring models and do not conflict. Both vectors specify PR:H, while the advisory separately documents exploitation by a default Rancher user. The advisory does not reconcile the two, so we recommend basing exposure assessment on the concrete permission scenario rather than the metric alone.

Exploitation status

As of November 3, 2026, we found no evidence of active exploitation or attribution. CISA's ADP SSVC assessment (recorded 2026-11-02T16:13:30.631420Z) lists exploitation as none, automatable as no and technical impact as total. CVE Watchtower reporting dated November 3 states exploitation is not confirmed, and TheHackerWire reports no confirmed public exploit code or proof of concept, no KEV listing as of its November 2 record, and no known ransomware linkage. Kenzie Cuttler of Tulip Interfaces, Inc. Security Research reported the issue. The GitHub advisory was published October 29, 2026, and NVD publication followed on November 2, 2026.

Patch Information

Fixed releases

  • Fleet: v0.16.3, v0.15.8, v0.14.12 and v0.13.17
  • Rancher: v2.15.3, v2.14.7, v2.13.11 and v2.12.15

The security fix itself lives in Fleet. Rancher needs a compatibility change for the new authorization checks, so the advisory directs operators to upgrade Rancher and its bundled Fleet together.

On the v0.16 line the fix is PR #5969, "[v0.16] Restrict cross-namespace kubeconfig references", a backport of #5968 referencing GHSA-qfmw-gw96-ffcr and merged as commit 4f301adc. It is listed as the first change in the v0.16.3 release notes.

Layer 1: the Secret owner must opt in with a label

The patch removes the allowlist and replaces it with checkKubeConfigSecretReference() together with a new API constant, KubeConfigReferenceableFromLabel = "fleet.cattle.io/kubeconfig-referenceable-from":

func checkKubeConfigSecretReference(cluster *fleet.Cluster, secret *corev1.Secret) error { ns := kubeConfigSecretNamespace(cluster) if ns == cluster.Namespace { return nil } if secret != nil && secret.Labels[fleet.KubeConfigReferenceableFromLabel] == cluster.Namespace { return nil } if config.Get().AllowUnlabeledKubeConfigSecretNamespaces && isWellKnownFleetNamespace(ns) && (secret == nil || secret.Labels[fleet.KubeConfigReferenceableFromLabel] == "") { return nil } return fmt.Errorf("%w: secret %s/%s needs label %s=%s to be used by cluster %s/%s", ...) }

(The arguments to the final fmt.Errorf are shortened in the source material.)

This works because of Kubernetes RBAC. Only someone who can write Secrets in the Secret's namespace can set the label, so the credential owner decides which single namespace may use it. A tenant who controls only their own workspace cannot label the fleet-local Secret, so their reference is rejected. References within the same namespace are unchanged.

Every code path that previously read the Secret directly (importCluster, onConfig and teardownLocalAgent) now goes through a single helper, i.kubeConfigSecret(cluster), so none of them can skip the check. The helper also closes a small information leak. A missing Secret in another namespace returns the same error as an unlabeled one, so tenants cannot use Cluster status to enumerate Secrets in namespaces they cannot see.

Layer 2: a separate management cluster check

The label alone is not treated as sufficient. After building a client from the kubeconfig, importCluster calls i.checkManagementClusterTarget(cluster, kc), which compares the UID of the kube-system namespace seen through the kubeconfig with the management cluster's own UID. If they match, an agent is deployed only when the Cluster lives in one of:

  • the bootstrap namespace (fleet-local by default)
  • the controller's system namespace
  • the controller's registration namespace

Otherwise the import fails with an error stating that the kubeconfig "targets the management cluster". Per the PR, this applies to every kubeconfig source, including Secrets in the Cluster's own namespace. A copied or labeled admin kubeconfig therefore still cannot be used to put an agent on local from a tenant workspace. A new end-to-end test copies the local-cluster Secret into a labeled namespace and confirms the import is rejected.

Behavior for existing agents and live changes

Previously, a Cluster with an already deployed agent exited early and was never validated again. Now importCluster still checks the reference for those clusters. A rejected reference appears in the Cluster's Imported condition, but the existing agent stays in place. The Secret index is now keyed only on the spec, and the Secret watch requeues every Cluster referencing a changed Secret, so adding or removing the label or changing the config flag takes effect without other edits.

Compatibility option

A new Helm value and config field, allowUnlabeledKubeConfigSecretNamespaces, defaults to false. Setting it to true restores the old behavior for unlabeled Secrets in the well-known namespaces (fleet-local, fleet-default, and the Fleet system and registration namespaces), with three limits:

  • A Secret with a nonempty label can still only be used from the namespace the label names.
  • Generated cluster- namespaces and arbitrary namespaces such as kube-system remain rejected.
  • The Layer 2 management cluster check still runs.

The advisory states this option weakens protection and should be used only until affected Secrets are labeled. We would treat it as a temporary compatibility exception, not a mitigation.

Rancher's part

Rancher stores the kubeconfig Secret for clusters assigned to workspaces other than fleet-default in fleet-default. Patched Rancher adds and maintains the label on those Secrets automatically. Administrators who manage cross-namespace kubeconfig Secrets themselves must add the label. Otherwise those clusters are no longer imported:

kubectl -n kubeconfigs label secret my-cluster-kubeconfig fleet.cattle.io/kubeconfig-referenceable-from=clusters

Tests

The PR adds roughly 1,100 lines across 13 files, mostly tests:

  • table-driven unit tests for checkKubeConfigSecretReference, kubeConfigSecret and checkManagementClusterTarget
  • envtest integration tests in integrationtests/agentmanagement/cluster_import_test.go
  • an end-to-end suite that replays the original attack path, a workspace Cluster referencing the local-cluster Secret

If you cannot upgrade immediately

The advisory states that no Fleet configuration option fully prevents this issue on affected versions. It lists these exposure reduction measures:

  • Remove workspace self-service: use custom or amended global roles so ordinary users do not receive create on management.cattle.io fleetworkspaces. Validate against your tenancy model, since this removes an intentional capability.
  • Restrict Fleet object creation: review bindings that grant write access to fleet.cattle.io clusters and bundles in nonsystem namespaces, and limit them to administrators and trusted operators.
  • Reject unauthorized Secret references: use an admission or policy controller such as Kubewarden to deny tenant Cluster creates or updates when kubeConfigSecretNamespace points outside the object's namespace. Legitimate Rancher workspace references to fleet-default need explicit exceptions.
  • Monitor: alert on unexpected Fleet agent namespaces and deployments on local, and on new ClusterRoleBinding objects granting cluster-admin.

Detection Methods

No public YARA, Sigma, Snort/Suricata or Nuclei signatures exist, and no static IoCs such as hashes or IPs have been published. That fits the bug. The attacker sends ordinary authenticated Kubernetes API requests, and the import controller does the privileged work with its own rights. Detection therefore relies on Kubernetes object state and audit telemetry on local, at three points: the bad reference, what the controller does next, and the resulting privilege.

1. Identify vulnerable deployments

Compare both the Rancher and Fleet versions against the fixed releases above. Rama Digital's write-up reads the server-version and fleet-version objects (settings.management.cattle.io) with kubectl. Without cluster access, it reads the unauthenticated /rancherversion endpoint, which returns only the Rancher version, not the Fleet version. Also check which global roles grant create on fleetworkspaces and how many users are bound to them, since the default user role allows it.

2. Hunt for cross-namespace kubeconfig references

This is the highest-signal check. List every Fleet cluster with its namespace and the namespace of its referenced Secret:

kubectl get clusters.fleet.cattle.io -A -o jsonpath='{range .items[*]}{.metadata.namespace}{"|"}{.metadata.name}{"|"}{.spec.kubeConfigSecretNamespace}{"\n"}{end}'

Triage the output:

  • Same namespace, or empty: normal.
  • Points to fleet-default: may be legitimate, because Rancher stores kubeconfig Secrets for clusters in other workspaces there. Confirm the owner.
  • Points to fleet-local: treat as a strong sign of compromise, because that namespace holds the management cluster's own credentials.

The advisory's admission rule doubles as an audit log alert. A create or update of clusters.fleet.cattle.io outside Fleet's system namespaces whose kubeConfigSecretNamespace differs from its own namespace is suspect. Run it continuously, not just as a one-time sweep.

3. Watch the precursors in audit logs

TheHackerWire's AI-assisted analysis recommends flagging Fleet Cluster creates or edits by nonadministrative users. The Rama Digital script adds a check for new fleetworkspaces.management.cattle.io objects other than fleet-default and fleet-local, and the field.cattle.io/creatorId annotation shows who created them. An ordinary user creating a workspace and then a Cluster with a foreign Secret reference is the attack sequence in miniature.

4. Detect the consequences

SUSE's advisory names two alert conditions:

  • New Fleet agent namespaces or deployments on local. The legitimate local agent lives in cattle-fleet-local-system. A fleet-agent deployment in any other namespace on the management cluster indicates the controller was made to manage it on a tenant's behalf.
  • New ClusterRoleBinding objects whose roleRef is cluster-admin. Compare creation times against change records. Rancher-generated bindings for global admins, named globaladmin-*, are normally expected but should still be verified.

More broadly, alert on Fleet bundle content landing on the management cluster when it traces back to a user-controlled Cluster definition.

5. Post-patch signals

Upgrading does not remove agents that were already deployed, so hunt backwards in time. After upgrading:

  • Monitor Imported conditions for rejections. A rejection tied to a tenant namespace may indicate an attempted attack or one that happened before the upgrade.
  • Audit which Secrets carry fleet.cattle.io/kubeconfig-referenceable-from and which namespaces the label values allow.
  • Alert on allowUnlabeledKubeConfigSecretNamespaces: true as a weakening of the protection.

Hunting notes

Run checks over a window that starts before the patch date. If you find even one strong sign, preserve Rancher and Kubernetes audit logs before cleanup. Because downstream credentials live on local, one hit means the whole managed fleet may be exposed. A clean result does not prove safety, since an attacker with cluster-admin can delete objects and logs, so back these checks with off-cluster audit log retention. TheHackerWire also suggests Shodan queries such as http.title:"Rancher" to find internet-exposed Rancher interfaces. This only maps attack surface and cannot show vulnerability or exploitation, because the attack requires a valid account.

Affected Systems and Versions

SUSE Rancher Fleet, as bundled with Rancher, in these ranges:

  • 0.16: 0.16.0 through versions before 0.16.3 (fixed in 0.16.3)
  • 0.15: 0.15.0 through versions before 0.15.8 (fixed in 0.15.8)
  • 0.14: 0.14.0 through versions before 0.14.12 (fixed in 0.14.12)
  • 0.13: 0.13.0 through versions before 0.13.17 (fixed in 0.13.17)

The CVE description's phrase "up to" should not be read as including the fixed versions. The CVE record also says "possible older versions", so releases outside these families should not automatically be treated as unaffected. The corresponding patched Rancher releases are v2.15.3, v2.14.7, v2.13.11 and v2.12.15.

The vulnerable configuration is the default one. Fleet is enabled by default, ordinary users with the user global role can create Fleet workspaces, and no additional feature or nondefault setting is required.

Vendor Security History

The most relevant comparison is CVE-2026-88808 (GHSA-q9v4-358v-r8q5), listed in SUSE's index on September 23, 2026. There, the Fleet agent wrote downstream resources with its own administrator credentials rather than the deployment's pinned ServiceAccount, letting a tenant able to create a Bundle, GitRepo or HelmOp write or overwrite Secrets and ConfigMaps across targeted downstream namespaces. Fleet v0.16.2, v0.15.7 and v0.14.11 fixed it by performing writes and namespace creation with the pinned ServiceAccount. Those releases do not fix CVE-2026-94290. The earlier flaw concerns which identity performs downstream writes, while this one concerns which credentials a tenant object can make the management controller use. A fix at one boundary does not establish protection at the other.

Other recent Rancher entries in SUSE's index:

  • CVE-2026-88805 (September 23, 2026; Rancher v2.15.2): logout cleared browser cookies but left the public API session token valid until expiry. Only deployments using these tokens are affected.
  • CVE-2026-75034 (August 27, 2026; Rancher v2.15.1, v2.14.5, v2.13.9): ineffective SAML replay protection in deployments with multiple replicas allowed a captured assertion to create additional victim sessions.

On process, Rancher commits to publishing advisories and CVEs for resolved issues, SUSE accepts vulnerability reports at [email protected], and the rancher/scans repository publishes daily Trivy-based image scan reports.

References

Detect & fix
what others miss

Works with
  • GitHub
  • GitLab
  • Bitbucket
  • Azure DevOps Services
  • Gerrit
  • CVS
  • Jira
  • Linear
  • Slack
  • Security Compass
Explore integrations
Security magnifying glass visualization