CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-39961
6.80.03%

CVE-2026-39961: Cross-Namespace Secret Exfiltration via Confused Deputy in Aiven Operator

Alon Barad
Alon Barad
Software Engineer

Apr 10, 2026·9 min read·0 visits

No Known Exploit

Executive Summary (TL;DR)

A confused deputy vulnerability in Aiven Operator allows attackers with restricted CRD creation privileges to exfiltrate secrets from arbitrary namespaces by manipulating the connInfoSecretSource configuration.

The Aiven Operator for Kubernetes (versions 0.31.0 through 0.36.x) contains a critical privilege escalation and data exfiltration vulnerability. A low-privileged user with permission to create specific Custom Resource Definitions (CRDs) can exploit a confused deputy flaw in the operator's reconciliation loop to read sensitive Kubernetes Secrets from any namespace in the cluster.

Vulnerability Overview

The Aiven Operator is a Kubernetes extension that manages Aiven cloud services directly from a Kubernetes cluster via Custom Resource Definitions (CRDs). It operates using the standard controller pattern, running an asynchronous reconciliation loop that continuously observes the cluster state and makes API calls to Aiven to ensure the declared state matches the actual state. To perform these duties, the operator requires broad permissions within the cluster, typically granted via a ClusterRole. This ClusterRole includes the ability to read, list, and watch standard Kubernetes Secret resources across all namespaces, which is necessary for the operator to access connection credentials and API tokens required for service provisioning.

CVE-2026-39961 represents a classic confused deputy vulnerability within the Aiven Operator's handling of specific CRDs, notably ClickhouseUser and ServiceUser. The vulnerability class is documented as CWE-441 (Unintended Proxy or Intermediary) and CWE-269 (Improper Privilege Management). The core issue arises because the operator exposes a configuration interface that allows users to define the source namespace of a secret without enforcing corresponding access controls on that user. When the operator processes the CRD, it uses its own high-privileged service account to fulfill the user's request, inadvertently bypassing the Kubernetes role-based access control (RBAC) boundaries that normally restrict the user.

The impact of this vulnerability is measured at a CVSS v3.1 score of 6.8 (Medium). While the privileges required (PR:H) mitigate the risk by ensuring the attacker already possesses specific access to the cluster, the scope change (S:C) and high confidentiality impact (C:H) reflect the severity of the data exposure. An attacker restricted to a single, isolated namespace can leverage the operator to extract highly privileged credentials, such as production database passwords or cluster-admin service account tokens, from completely distinct administrative namespaces.

Root Cause Analysis

The fundamental root cause of CVE-2026-39961 is the unvalidated acceptance of user-controlled namespace parameters within the CRD specification combined with the operator's global secret-reading privileges. The ClickhouseUser and ServiceUser CRDs utilize a nested structure named connInfoSecretSource to define where the operator should retrieve connection credentials. Prior to the fix, this structure included an optional namespace string field. The design intent was likely to provide flexibility, allowing users to consolidate secrets in a centralized namespace while deploying CRDs across various development environments.

During the reconciliation cycle, the controller manager triggers the Reconcile method for the respective CRD. The controller extracts the connInfoSecretSource configuration and invokes the GetPasswordFromSecret function. At this stage, the operator evaluates the provided configuration. The vulnerable logic explicitly checked if the user supplied a custom namespace in the CRD payload. If a custom namespace was provided, the operator adopted it; otherwise, it defaulted to the namespace of the CRD itself. The controller did not verify whether the creator of the CRD possessed get or list permissions for secrets in the specified target namespace.

Because the operator runs under the aiven-operator-role ClusterRole, the standard Kubernetes API server authorizes the secret retrieval. The API server evaluates the authorization context of the operator's service account, not the authorization context of the user who applied the YAML manifest. This is the essence of a confused deputy flaw: the operator (the deputy) is tricked into utilizing its elevated privileges to perform an action on behalf of a lower-privileged entity (the user). After retrieving the target secret, the operator projects the secret data into a new Secret resource located in the attacker's namespace, completing the exfiltration chain.

Code Analysis

The vulnerability is localized within the controllers/secret_password_manager.go file, specifically within the logic responsible for fetching user-defined secrets. The vulnerable implementation trusted the Namespace field populated directly from the parsed YAML manifest.

// VULNERABLE CODE
func (m *SecretPasswordManager) GetPasswordFromSecret(ctx context.Context, secretSource *api.ConnInfoSecretSource, resource client.Object) (string, error) {
    sourceNamespace := secretSource.Namespace
    if sourceNamespace == "" {
        // Fallback to the resource's namespace only if the user didn't specify one
        sourceNamespace = resource.GetNamespace()
    }
 
    sourceSecret := &corev1.Secret{}
    err := m.k8sClient.Get(ctx, types.NamespacedName{
        Name:      secretSource.Name,
        Namespace: sourceNamespace, // TRUSTED USER INPUT
    }, sourceSecret)
    // ... secret processing ...
}

The patch applied in commit 032c9ba63257fdd2fddfb7f73f71830e371ff182 resolves the issue by entirely removing the operator's ability to cross namespace boundaries for this specific operation. The vendor chose a structural fix over an authorization-check fix. The Namespace field was removed from the ConnInfoSecretSource struct in api/v1alpha1/common.go. Consequently, the controller logic was simplified to strictly enforce the namespace of the origin resource.

// PATCHED CODE
func (m *SecretPasswordManager) GetPasswordFromSecret(ctx context.Context, secretSource *api.ConnInfoSecretSource, resource client.Object) (string, error) {
    ns := resource.GetNamespace() // STRICTLY ENFORCE RESOURCE NAMESPACE
 
    sourceSecret := &corev1.Secret{}
    err := m.k8sClient.Get(ctx, types.NamespacedName{
        Name:      secretSource.Name,
        Namespace: ns, // NO USER INPUT ALLOWED
    }, sourceSecret)
    // ... secret processing ...
}

By discarding the user-supplied namespace and relying entirely on resource.GetNamespace(), the operator restricts secret reads to the same namespace as the CRD. This enforces the correct security boundary: if a user has permission to create a CRD in namespace A, the operator will only read secrets from namespace A to fulfill that CRD's requirements. The user inherently requires access to namespace A to execute the attack, making the operation secure. The fix is complete and effectively eliminates this specific confused deputy vector.

Exploitation and Attack Methodology

Exploitation of CVE-2026-39961 requires the attacker to hold specific RBAC permissions within the target Kubernetes cluster. The attacker must be able to create instances of the ClickhouseUser or ServiceUser custom resources. This privilege is typically granted to developers or automation pipelines responsible for provisioning database infrastructure within restricted development or staging namespaces.

The attack begins with reconnaissance. The attacker must identify the name and namespace of a target secret they wish to exfiltrate. While Kubernetes prevents unauthorized listing of secrets across the cluster, attackers often target well-known secrets, such as default service account tokens in the kube-system namespace, generic tls-certs, or standard naming conventions like prod-db-credentials in a production namespace. Once a target is identified, the attacker crafts a malicious CRD manifest.

apiVersion: aiven.io/v1alpha1
kind: ClickhouseUser
metadata:
  name: malicious-exfiltrator
  namespace: attacker-controlled-ns
spec:
  project: default-project
  serviceName: default-service
  connInfoSecretSource:
    name: cluster-admin-token
    namespace: kube-system  # TARGET NAMESPACE
    passwordKey: token
  connInfoSecretTarget:
    name: exfiltrated-secret # DESTINATION IN ATTACKER NS

The attacker applies this manifest to the cluster using standard API interactions (kubectl apply -f payload.yaml). The Kubernetes API server accepts the resource because the attacker is authorized to create ClickhouseUser objects in attacker-controlled-ns. The Aiven Operator's reconciliation loop subsequently detects the new resource. Operating with its elevated privileges, the controller fetches kube-system/cluster-admin-token and writes its contents to attacker-controlled-ns/exfiltrated-secret. The attacker then reads the newly created secret from their own namespace, successfully circumventing their RBAC restrictions.

Impact Assessment

The successful exploitation of this vulnerability directly undermines the fundamental tenant of Kubernetes multi-tenancy and namespace isolation. Namespaces are the primary mechanism for dividing cluster resources between multiple users. By breaking this boundary, an attacker escalates their privileges from a scoped developer role to the highest level of cluster access, depending on the secrets they target. The CVSS vector (CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N) accurately reflects the scope change, as the vulnerable component (the operator) affects resources managed by a different authority (the cluster administrator).

The most critical risk involves the theft of high-value service account tokens. If an attacker targets the kube-system namespace and extracts a token bound to the cluster-admin role, they achieve complete cluster compromise. With cluster-admin privileges, the attacker can deploy malicious daemonsets, manipulate node configurations, access all data stored within the cluster, and potentially pivot to the underlying cloud provider infrastructure if the cluster utilizes permissive IAM role binding (e.g., AWS IAM Roles for Service Accounts).

Beyond cluster compromise, the vulnerability facilitates broad data exfiltration. Attackers can extract TLS private keys, allowing them to decrypt intercepted cluster traffic or impersonate internal services. They can also target application-specific secrets, such as database connection strings, API keys for external services, or encryption keys used for data at rest. This broadens the blast radius of the attack beyond the Kubernetes environment and into the organization's broader infrastructure and third-party service dependencies.

Remediation and Mitigation Guidance

The definitive remediation for CVE-2026-39961 is upgrading the Aiven Operator to version 0.37.0 or later. This release fundamentally alters the API schema by removing the namespace field from the connInfoSecretSource specification and hardening the controller logic to strictly utilize the namespace of the origin resource. Organizations utilizing automated deployment pipelines (e.g., ArgoCD, Flux) should update their Helm chart or kustomize references to ensure the patched version is deployed across all environments.

In scenarios where immediate patching is administratively prohibitive, organizations can implement mitigating controls using Kubernetes admission controllers. Tools such as Open Policy Agent (OPA) Gatekeeper or Kyverno can enforce policies that reject any ClickhouseUser or ServiceUser custom resource attempting to specify the namespace field. A Kyverno validating webhook can be configured to inspect the spec.connInfoSecretSource.namespace path and block the API request if the field is present, effectively neutralizing the attack vector at the API server level before the operator ever processes the payload.

Security teams should also review audit logs for historical exploitation. Kubernetes API server audit logs should be queried for create or update events targeting clickhouseusers.aiven.io or serviceusers.aiven.io resources where the request payload contains a namespace declaration within the connInfoSecretSource block. Any such events warrant immediate investigation to determine if unauthorized secret access occurred.

Official Patches

AivenRelease v0.37.0 containing the fix

Fix Analysis (1)

Technical Appendix

CVSS Score
6.8/ 10
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:H/I:N/A:N
EPSS Probability
0.03%

Affected Systems

Aiven Operator (Kubernetes Operator)

Affected Versions Detail

Product
Affected Versions
Fixed Version
aiven-operator
Aiven
v0.31.0 - < v0.37.0v0.37.0
AttributeDetail
CWE IDCWE-269, CWE-441
Attack VectorNetwork (via Kubernetes API)
CVSS Score6.8 (Medium)
EPSS Score0.00025 (0.03% probability)
ImpactCross-Namespace Secret Exfiltration
Exploit StatusNone public
KEV StatusNot Listed

MITRE ATT&CK Mapping

T1068Exploitation for Privilege Escalation
Privilege Escalation
CWE-269
Improper Privilege Management

The software does not properly assign, modify, track, or check privileges for an actor, creating an unintended sphere of control for that actor. This serves as a confused deputy allowing unauthorized actions.

Vulnerability Timeline

Security advisory created for Aiven Operator.
2026-04-08
Fix commit merged to main branch.
2026-04-09
CVE-2026-39961 published and fixed version v0.37.0 released.
2026-04-09

References & Sources

  • [1]GitHub Security Advisory: GHSA-99j8-wv67-4c72
  • [2]CVE Org Record: CVE-2026-39961

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.