Short answer: before version 2.13.0, yes, in some configurations. Advisory GHSA-v6x5-m838-gqph (CVE-2026-109546) says that a user who can only create ExternalSecret resources could escalate privileges. That user could make External Secrets Operator (ESO) create a Secret that Kubernetes fills with a long-lived token for a service account, and so impersonate any service account in that namespace. Versions 2.4.0 through 2.12.0 are listed as affected, and 2.13.0 contains the fix. Upgrade first, then check who may create ExternalSecrets. The advisory rates the issue moderate (CVSS 4.9, high attack complexity, low privileges required), because the attacker needs permissions that are already close to powerful.

This article is based on the advisories, release notes, source code and documentation, all opened on October 27, 2026. We did not have a cluster, did not reproduce the issue and did not test any command below. Snippets marked "untested" are our own drafts. Check them in a non-production cluster first.

What does the advisory say?

Short answer: it describes a privilege escalation from "can create ExternalSecrets" to "can act as any service account in the namespace", fixed in 2.13.0.

Facts from the advisory, published on October 16, 2026:

  • Severity: Moderate, CVSS 4.9 (CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:L/I:L/A:N).
  • Affected: >= 2.4.0, <= 2.12.0. Patched: 2.13.0.
  • Impact, in the advisory's words: the user can cause the operator to create a Secret that Kubernetes will "automatically populate with a long-lived token for the specified service account". The user does not need direct permission to create Secrets of that type or to call TokenRequest.
  • Cause: it is a follow-up to CVE-2026-42876 (GHSA-fq7h-9x26-6j22, published May 5, 2026, fixed in 2.4.1). That earlier fix validated input before a Secret was created or updated. According to the new advisory, the guard could be bypassed with a target that behaves like Annotations without matching that exact string, such as metadata.annotations or a mixed-case Metadata.Annotations. The fix rejects path-style targets for Secrets.
  • Workarounds listed: add admission control that blocks templates targeting undesired types, remove service account token generation through kube-controller-manager flags, and restrict user RBAC in production clusters and sensitive namespaces.

The advisory contains no proof of concept, and neither does this article.

How does an operator that syncs secrets end up minting tokens?

Short answer: the operator only writes a Secret of a special type; a Kubernetes controller fills in the token.

Kubernetes documents kubernetes.io/service-account-token as a legacy Secret type that "provides long-lived ServiceAccount credentials". The Secret must carry the annotation kubernetes.io/service-account.name with the name of an existing service account. After it is created, "a Kubernetes controller fills in" the token key and related annotations. That controller is the token controller inside kube-controller-manager.

ESO lets an ExternalSecret shape the Secret it produces through spec.target.template, which can set the Secret's type, metadata and data. This is intended and useful. It also means that whoever writes an ExternalSecret influences what kind of Secret the operator creates with its own, broader permissions. So ESO's validation refuses the dangerous combination: in the code at v2.13.0, a template of type kubernetes.io/service-account-token is rejected when it carries the service-account annotation, and the type bootstrap.kubernetes.io/token is always rejected. The advisory is about inputs that slipped past this check in versions up to 2.12.0.

Where does the code differ between 2.12.0 and 2.13.0?

Short answer: 2.13.0 adds a check on the final Secret and tightens which template targets are allowed. We could not map the advisory to one exact input.

The 2.13.0 release notes list three relevant changes by one author: "fix: validate manifest Secret candidates" (#7066), "fix: Restrict v1beta1 Secret template targets" (#7067, which concerns the v1beta1 validator) and a test for the reconcile step (#7068). The release notes do not mention the CVE.

The pull request descriptions frame the gap in two ways. #7066 says that an ExternalSecret targeting a core/v1 Secret through manifest "can be used to bypass the protections used by the normal Secret reconciliation path". #7067 says the v1beta1 validator "previously allowed templateFrom targets outside the well-known Secret data, annotation, and label destinations". The advisory talks about path-style annotation targets. These are probably related, but we have not confirmed that they describe the same input, so treat the mapping as our inference.

There is one more oddity. The validator in v2.11.0 and v2.12.0 already contains an allowlist (targets Data, Annotations or Labels), yet the advisory lists them as affected. Do not rely on your own reading of the code to decide that you are safe. Follow the advisory's range.

The code comment says the controller calls the same rules "so the same set is enforced when no webhook sits in front of it". That suggests the check exists both in the admission webhook and in the controller. If you run ESO with the webhook disabled or with failurePolicy: Ignore, only the controller-side checks apply. The chart default is webhook.create: true with failurePolicy: Fail.

Are you affected?

Short answer: you are if you run ESO 2.4.0 to 2.12.0 and anyone who is not a cluster admin can create or update ExternalSecrets.

Work through these in order:

  1. Version. Check the image tag of the controller deployment. Anything from 2.4.0 to 2.12.0 is in the advisory's range. Versions before 2.4.1 are listed as affected by the earlier CVE-2026-42876, so upgrade them too.
  2. Who can write ExternalSecrets? In many clusters, developers get create on externalsecrets in their team namespace. Those are exactly the users the advisory is about. kubectl auth can-i create externalsecrets.external-secrets.io -n <namespace> --as=<user> answers it for one user, but it needs impersonation rights. Also look at ClusterExternalSecret, which creates ExternalSecrets in many namespaces.
  3. Existing objects. An audit sketch (untested, needs jq):
# ExternalSecrets with unusual templates (read-only)
kubectl get externalsecrets -A -o json | jq -r '
  .items[] | select(
    (.spec.target.template.type // "" | test("service-account-token|bootstrap"; "i"))
    or (.spec.target.template.metadata.annotations // {} | keys | any(test("service-account"; "i")))
    or ([.spec.target.template.templateFrom[]?.target // ""]
        | any(test("^(|data|annotations|labels)$"; "i") | not))
    or (.spec.target.manifest != null)
  ) | "\(.metadata.namespace)/\(.metadata.name)"'

# Service account token Secrets owned by an ExternalSecret
kubectl get secrets -A -o json | jq -r '
  .items[]
  | select(.type == "kubernetes.io/service-account-token")
  | select(any(.metadata.ownerReferences[]?; .kind == "ExternalSecret"))
  | "\(.metadata.namespace)/\(.metadata.name)"'

The second query assumes the default creationPolicy, under which the operator sets an owner reference. We did not verify that, so a Secret created under another policy may not appear. A hit in either list is a reason to look, not proof of abuse; legitimate uses of manifest exist. If the cluster has audit logging, search it for create and update events on externalsecrets whose template type contains service-account.

What should you do?

Short answer: upgrade, narrow who can write ExternalSecrets, consider a native agent, and add an admission rule for template types.

1.Upgrade to 2.13.0 or later. The latest release when we checked was 2.14.0 (October 23, 2026). Its notes list some security-related hardening, for example "Sanitize Controller Status and Event Errors", but nothing about this advisory. So 2.14.0 is a normal upgrade target, not a second fix. Read the notes for your jump, because version 2.13.0 also bumped the Go toolchain.

2. Restrict RBAC. Treat create and update on externalsecrets as a sensitive permission. ESO's security guide says: "It is crucial to properly restrict access to ESO resources such as ExternalSecret and SecretStore where necessary". The chart supports scopedRBAC and scopedNamespace to limit what the controller reconciles. For ClusterSecretStore, the docs show conditions with a namespaceSelector, so only labelled namespaces may reference it.

3. Add admission control. This is a workaround from the advisory, and ESO's docs do not ship a ready policy for template types. As an example, a native ValidatingAdmissionPolicy could deny templates that produce the two risky types. This is our draft and untested:

apiVersion: admissionregistration.k8s.io/v1
kind: ValidatingAdmissionPolicy
metadata:
  name: eso-deny-sa-token-template
spec:
  failurePolicy: Fail
  matchConstraints:
    resourceRules:
    - apiGroups: ["external-secrets.io"]
      apiVersions: ["*"]
      operations: ["CREATE", "UPDATE"]
      resources: ["externalsecrets"]
  validations:
  - expression: >-
      !has(object.spec.target) || !has(object.spec.target.template) ||
      !has(object.spec.target.template.type) ||
      !(object.spec.target.template.type in
        ["kubernetes.io/service-account-token", "bootstrap.kubernetes.io/token"])
    message: "ExternalSecret templates must not create service account token or bootstrap token Secrets"

It also needs a ValidatingAdmissionPolicyBinding with validationActions: [Deny]. It does not cover spec.target.manifest, a type set through other fields, or ClusterExternalSecret, where the spec is nested under spec.externalSecretSpec. Use it as a starting point and extend it, or write the equivalent in Kyverno or Gatekeeper.

4. Consider disabling legacy token generation. The Kubernetes docs say the token controller needs --service-account-private-key-file, and the reference describes that flag as "Enables legacy secret-based tokens when set". --controllers=*,-serviceaccount-token-controller is a documented way to disable that controller. We could not verify the side effects. Workloads or CI jobs that still use legacy token Secrets would break, and managed Kubernetes services may not expose these flags.

5. Evaluate native sync agents over custom operators. This CVE highlights the inherent risk of using Custom Resource Definitions (CRDs) like ExternalSecret as an intermediary layer for secret management. If a user can write to the CRD, they can manipulate the operator's broader permissions. As an architectural alternative, Ennote's Kubernetes Smart Agent eliminates the need for External Secrets Operator entirely. It uses an outbound gRPC stream to push secrets directly into native Kubernetes Secrets in under one second without requiring ExternalSecret custom resources, sidecars, or inbound firewall rules.

6. Rotate if you find a suspicious token. Delete the Secret and any ExternalSecret that produced it, then review what the token could reach. The Kubernetes docs say the token controller removes the token Secrets of a deleted ServiceAccount. We did not verify whether deleting a legacy token Secret alone revokes the token, so also consider recreating the affected ServiceAccount. For the general order of actions after a credential has leaked, see our guide on what to do when an API key leaks.

What does not help?

Short answer: rbac.serviceAccountTokenCreate: false is not a mitigation for this advisory, as far as we can tell.

ESO's security guide mentions that the controller role includes a blanket serviceaccounts/token: create permission and that you can turn it off with rbac.serviceAccountTokenCreate: false. The chart comment describes it as the serviceaccounts/token create permission, needed for ServiceAccounts referenced in SecretStore specs (serviceAccountRef). The token in this advisory is a different thing: a legacy Secret populated by kube-controller-manager. Reading the chart and the Kubernetes docs, the setting does not touch that path. This is our reasoning, and ESO's docs do not say either way. Turn it off for least privilege, but not as a fix for this advisory.

According to the advisory, the first fix could be bypassed with an alternative spelling of the target, so validation now also runs on the final Secret. The practical lesson is defense in depth: the cluster, not only the operator, should refuse to hand a user a long-lived credential they should not hold.

Sources


Keep long-lived credentials out of cluster-wide reach. Ennote is a secret manager for passwords, API keys, and environment variables, with role-based access, an audit log, and native Kubernetes synchronization. By replacing custom operators with our Smart Agent, you remove the RBAC complexity that leads to privilege escalation. Start for free on the Developer plan.