CVE-2026-65835: Capsule: Incomplete fix of CVE-2026-22872: TenantResource RawItems and Generators still allow cluster-scoped resource creation (cross-tenant privilege escalation)

Published Jul 30, 2026
·
Updated

Summary CVE-2026-22872 (GHSA-qjjm-7j9w-pw72) reported that a Tenant Owner could create cluster-scoped resources (e.g. ClusterRole, ValidatingWebhookConfiguration) through a TenantResource, because the controller applies them with its cluster-admin ServiceAccount and SetNamespace is ineffective for cluster-scoped kinds. The v0.13.0 fix added a cluster-scope rejection guard, but only on the NamespacedItems selection path (ResourceReference.LoadResources -> IsNamespacedGVK, error "cluster-scoped kind ... is not allowed"). The RawItems create path — the exact vector the original advisory named — and the Generators path were not given this guard. The vulnerability therefore persists in all releases v0.13.0 through v0.13.7 and on trunk HEAD (8d89d6865d).

Details TenantResource reconcile flow: - internal/controllers/resources/namespaced.go reconcile() obtains the apply client via loadClient(); by default (impersonation off, no Spec.ServiceAccount) this is the manager client whose SA is bound to cluster-admin (charts/capsule/templates/rbac.yaml:488-501, {fullname}-manager-rolebinding -> roleRef cluster-admin). - Collector.Collect() (collect.go) processes spec.RawItems via handleRawItem and spec.Generators via handleGeneratorItem.

handleRawItem (collect.go:406-425, trunk HEAD — byte-identical to v0.13.0): go tmplString := tpl.FastTemplate(string(item.Raw), opts.Iterator.FastContext) obj := &unstructured.Unstructured{} unstructured.UnstructuredJSONScheme.Decode([]byte(tmplString), nil, obj) if ns != nil { obj.SetNamespace(ns.Name) } // ONLY mitigation return obj, nil // NO IsNamespacedGVK / allowClusterScoped guard handleGeneratorItem (collect.go:382-404) is the same: it only SetNamespaces on rendered objects.

The accumulated objects flow to pkg/api/processor/processorfunc.go Reconcile() -> Apply() -> clt.PatchApply(ctx, c, obj, ...) (line 167/378) with no scope check at any point.

By contrast, CollectNamespacedItems (collect.go:308) calls item.LoadResources(..., allowClusterScoped=false), and pkg/template/reference.go:105-107 enforces: go if !allowClusterScoped && !isNamespaced { return nil, fmt.Errorf("cluster-scoped kind %s/%s is not allowed", ...) } So the guard the fix added is real, but it sits on a different (selection) path than the one the CVE described (RawItems create path). For cluster-scoped kinds, SetNamespace is ignored by the Kubernetes API server, so the object is created cluster-wide by the cluster-admin client.

Parent-fix diff confirmation: in v0.12.4 the RawItems handler in processor.go was the vulnerable code (obj.SetNamespace(ns.Name) then createOrUpdate via r.client). v0.13.0 refactored this into collect.go handleRawItem but left it without the new guard.

Proof of Concept A self-contained in-process Go test (incompletefixpoctest.go), run against trunk HEAD with go1.26.4, proves the asymmetry: - TestRawItemPathNoClusterScopeGuard: feeds a ClusterRole rawItem to handleRawItem -> object returned unchanged, no rejection (PASS). - TestNamespacedItemsPathHasClusterScopeGuard: feeds the same ClusterRole kind to LoadResources(allowClusterScoped=false) -> rejected with "cluster-scoped kind rbac.authorization.k8s.io/v1/ClusterRole is not allowed" (PASS).

VULNERABLE: RawItems path accepted cluster-scoped rbac.authorization.k8s.io/v1/ClusterRole; metadata.namespace="tenant-ns" (ignored by API server for cluster-scoped kinds) GUARDED: NamespacedItems path correctly rejected cluster-scoped kind: cluster-scoped kind rbac.authorization.k8s.io/v1/ClusterRole is not allowed

End-to-end (cluster) reproduction: 1. Deploy capsule (default Helm) with rbac.resources.create=true (the opt-in that exposes TenantResources to tenant owners; the configuration the original CVE applies to). 2. As a Tenant Owner, create in a tenant namespace: yaml apiVersion: capsule.clastix.io/v1beta2 kind: TenantResource metadata: {name: pwn, namespace: <tenant-ns>} spec: resources: - namespaceSelector: {matchLabels: {capsule.clastix.io/tenant: <tenant>}} rawItems: - apiVersion: rbac.authorization.k8s.io/v1 kind: ClusterRole metadata: {name: tenant-escalation} rules: [{apiGroups: [""], resources: [""], verbs: [""]}] 3. Observe the cluster-scoped ClusterRole tenant-escalation is created by the cluster-admin controller, despite the tenant owner lacking cluster RBAC to create it. Swap in ValidatingWebhookConfiguration to intercept/exfiltrate cluster-wide Secrets.

Impact A Tenant Owner (namespace-scoped) escalates to cluster-admin-equivalent privileges and can compromise all tenants and the cluster control plane. Identical impact to CVE-2026-22872; the v0.13.0 remediation does not close the RawItems/Generators vector.

Remediation Apply the same IsNamespacedGVK / allowClusterScoped rejection inside handleRawItem and handleGeneratorItem — or centrally in Collector.AddToAccumulation / processor.Apply — so the create path enforces the same cluster-scope policy as the selection path. (GlobalTenantResource shares the path but is not a privesc — cluster-admin-only to create.)

Other sources

Capsule is a multi-tenancy and policy-based framework for Kubernetes. From 0.13.0 until 0.13.8, after the incomplete CVE-2026-22872 fix, TenantResource RawItems and Generators in internal/controllers/resources/collect.go, including handleRawItem and handleGeneratorItem, did not apply the ResourceReference.LoadResources and IsNamespacedGVK cluster-scoped resource rejection guard used by NamespacedItems, allowing a Tenant Owner to create cluster-scoped resources such as ClusterRole or ValidatingWebhookConfiguration through the cluster-admin controller client. This issue is fixed in version 0.13.8.

MITRE

Affected Software

2 affected componentsFixes available
Capsule Capsule>=0.13.0<0.13.8
go/github.com/projectcapsule/capsule>=0.13.0<=0.13.7
0.13.8

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade go/github.com/projectcapsule/capsule to a version that resolves this vulnerability.

    Fixed in 0.13.8
  2. Upgrade

    Upgrade to a fixed release to a version that resolves this vulnerability.

    Fixed in 0.13.8
  3. Configuration

    If using the default Helm deployment, note that the opt-in `rbac.resources.create=true` exposes TenantResources; ensure it is not enabled unless required, because TenantResource RawItems/Generators can create cluster-scoped resources when the fix is not present.

    Capsule Helm chart (default) rbac.resources.create = true
  4. Compensating control

    Temporarily restrict Tenant Owner capabilities for TenantResource usage (e.g., avoid granting permissions that allow creation of TenantResource RawItems/Generators) until Capsule is upgraded to v0.13.8.

Event History

Jul 30, 2026
CVE Published
via MITRE·07:53 PM
Data Sourced
via MITRE·07:53 PM
DescriptionSeverityWeakness
Data Sourced
via NVD·08:18 PM
DescriptionSeverityWeakness
Jul 31, 2026
Advisory Published
via GitHub·04:53 PM
Data Sourced
via GitHub·04:53 PM
DescriptionSeverityWeaknessAffected Software
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Frequently Asked Questions

1

What is the severity of CVE-2026-65835?

The severity of CVE-2026-65835 is classified as medium with a score of 6.6.

2

What does CVE-2026-65835 affect?

CVE-2026-65835 affects the Capsule framework for Kubernetes, specifically from versions 0.13.0 to 0.13.8.

3

How do I fix CVE-2026-65835?

To fix CVE-2026-65835, upgrade Capsule to version 0.13.9 or later.

4

What kind of vulnerability is CVE-2026-65835?

CVE-2026-65835 is a cross-tenant privilege escalation vulnerability due to an incomplete fix of CVE-2026-22872.

5

What does the incomplete fix in CVE-2026-65835 allow?

The incomplete fix in CVE-2026-65835 allows the creation of cluster-scoped resources through TenantResource RawItems and Generators.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203