Shared Surface · Operators

Operators & DaemonSets

Operators and DaemonSets run powerful, shared code on behalf of every tenant. That makes them classic confused deputies — trusted components that can be tricked into acting on an attacker's behalf.

Operators are widely used in most Kubernetes clusters to provide additional features and functionality to users of the cluster. In a multi-tenant environment though, they can present risks of privilege escalation.

Another similar risk can be presented by DaemonSets, which are often used to provide system or cluster-wide functionality on every node.

A custom resource is a request to a privileged service

The easiest way I’ve found to think about operators is that creating a custom resource is really an API call to the operator. RBAC decides whether a tenant can create a resource of that type in their namespace, but the work is then done using the operator’s service account, which usually has rights across the whole cluster.

RBAC can answer “may this user create a ScaledObject in namespace X?”. What it can’t answer is “may this user get KEDA to send KEDA’s token to a URL of their choosing?”. So the effective privilege of “create this custom resource” is roughly everything the operator can be persuaded to do with its own credentials.

That matches what we’re seeing in practice. Looking at the operator, controller and policy engine CVEs published in 2026, 14 of 21 needed nothing more than the ability to create or update a namespaced resource, and a couple of the advisories (KEDA and the Grafana Operator) describe the outcome directly as namespace admin to cluster admin.

Confused deputies

The most common pattern is a tenant borrowing the operator’s authority. An operator resolves a reference supplied by the tenant (a namespace field, a template function, a policy callback) using its own credentials, and never checks whether the tenant could have accessed the target themselves.

The Breaking the Bulkhead paper (NDSS 2026) looked at this systematically. Scanning 2,268 open source Go operators, they found more than 14% were potentially vulnerable to cross-namespace reference issues, leading to 7 CVEs. ERNW’s research found the same shape in shared components like Istio and Traefik, which I’ve covered on the networking page.

There are a couple of other variations on the theme that come up a lot:

  • Stealing the operator’s credentials. Rather than borrowing the operator’s rights, the tenant gets the operator to send its service account token somewhere they control. KEDA (CVE-2026-77524) would send its token to a tenant-supplied “Vault” address, and the OpenTelemetry Operator (CVE-2026-47701) could be tricked into attaching its own token to scrape requests aimed at a tenant’s target. A stolen token works from outside the cluster and outlives the bug, so patching isn’t enough on its own, you also need to rotate the credential.
  • Programmable features. Templates, CEL expressions, Jsonnet and policy callbacks all run tenant-supplied logic with the operator’s privileges. A number of the 2026 fixes were simply removing or disabling the feature, which suggests some of these just aren’t safe in a multi-tenant cluster.

It’s not just third-party operators

The same problem can turn up in the core of Kubernetes. CVE-2026-2270 was a confused deputy in the StatefulSet controller in kube-controller-manager. A tenant with write access to statefulsets and controllerrevisions in their own namespace could forge a ControllerRevision that made the controller create a pod in a different namespace, with a spec the attacker chose. That pod could mount the victim namespace’s Secrets or run as one of its service accounts.

It’s fixed in v1.34.12, v1.35.9, v1.36.5 and v1.37.1, but it’s a good example of a permission that most people wouldn’t flag in an RBAC review.

DaemonSets and node compromise

The other risk is that these components often run with quite high privileges, which makes them a tempting target for an attacker who has managed to break out of a container onto the underlying node. DaemonSets run a pod on every node by design, so whatever service account tokens or APIs they expose are available on every node a tenant might land on.

This is one of the reasons dedicated node pools don’t completely solve the problem. Even with tenants on separate nodes, the cluster’s DaemonSets are still there on every one of them.

What can you do about it?

There’s no complete fix here, but there are a couple of things that help:

  • Pair up the custom resources tenants can create with the RBAC of the operator that handles them. That pairing is your tenant’s effective privilege. Watch out for API group wildcards and the aggregated edit/admin roles quietly granting access to operator resources.
  • Restrict operator egress. Most operators only need to talk to the API server and a few known endpoints. An egress network policy would have blocked the token-exfiltration paths above.
  • Shrink the operator’s rights. Least privilege can’t fix a confused deputy (the operator really does need its permissions), but it does decide how bad every other bug is. Cluster-wide Secret read is the big one to look out for.
  • Run per-tenant operator instances, or scope operators to watched namespaces, so a confused deputy can only reach its own tenant’s resources.
  • Score operator CVEs against your own tenancy model. “Namespace admin to cluster admin” isn’t much of an issue in a cluster run by one team, but it’s a full tenant break on a shared platform, and CVSS scores don’t really capture that.

References & further reading

← All shared surfaces