Summary
Capsule has an incomplete fix of CVE-2026-22872: TenantResource RawItems and Generators still allow cluster-scoped resource creation (cross-tenant privilege escalation)
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.goreconcile()obtains the apply client vialoadClient();
by default (impersonation off, noSpec.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) processesspec.RawItemsviahandleRawItemandspec.Generators
viahandleGeneratorItem.
handleRawItem (collect.go:406-425, trunk HEAD, byte-identical to v0.13.0):
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/processor_func.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:
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 intocollect.go handleRawItem but left it without the new guard.
Proof of Concept
A self-contained in-process Go test (incompletefix_poc_test.go), run against trunk HEAD with go1.26.4,
proves the asymmetry:
TestRawItemPath_NoClusterScopeGuard: feeds aClusterRolerawItem tohandleRawItem-> object returned
unchanged, no rejection (PASS).TestNamespacedItemsPath_HasClusterScopeGuard: feeds the sameClusterRolekind toLoadResources(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:
- 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). - As a Tenant Owner, create in a tenant namespace:
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: ["*"]}] - Observe the cluster-scoped ClusterRole
tenant-escalationis created by the cluster-admin controller,
despite the tenant owner lacking cluster RBAC to create it. Swap inValidatingWebhookConfiguration
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.
The application assigns, modifies, tracks, or checks privileges incorrectly, allowing a user to gain elevated access. Typical impact: privilege escalation beyond the intended level.
CVE-2026-65835 has a CVSS score of 6.6 (Medium). The vector is network-reachable, high privileges required, and no user interaction. A CVSS score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether this affects your application depends on whether the vulnerable code is present and reachable in your environment. A fixed version is available (0.13.8); upgrading removes the vulnerable code path.
Affected versions
Security releases
Kodem intelligence
Severity tells you how bad this could be in the worst case. It does not tell you whether you are exposed. Exploitability and impact are functions of runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A vulnerable package can sit in your dependency tree and never run.
Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter. Kodem's runtime-powered SCA identifies whether this CVE is reachable in your applications.
Already deployed Kodem?
See it in your environmentNew to Kodem? Get a demo →Remediation advice
Apply the same IsNamespacedGVK / allowClusterScoped rejection inside handleRawItem andhandleGeneratorItem, 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.)
Frequently Asked Questions
- What is CVE-2026-65835? CVE-2026-65835 is a medium-severity improper privilege management vulnerability in github.com/projectcapsule/capsule (go), affecting versions >= 0.13.0, <= 0.13.7. It is fixed in 0.13.8. The application assigns, modifies, tracks, or checks privileges incorrectly, allowing a user to gain elevated access.
- How severe is CVE-2026-65835? CVE-2026-65835 has a CVSS score of 6.6 (Medium). This score reflects the worst-case severity of the vulnerability, not your specific exposure. Whether it represents real risk in your environment depends on whether the vulnerable code is present and reachable.
- Which versions of github.com/projectcapsule/capsule are affected by CVE-2026-65835? github.com/projectcapsule/capsule (go) versions >= 0.13.0, <= 0.13.7 is affected.
- Is there a fix for CVE-2026-65835? Yes. CVE-2026-65835 is fixed in 0.13.8. Upgrade to this version or later.
- Is CVE-2026-65835 exploitable, and should I be worried? Whether CVE-2026-65835 is exploitable in your environment depends on whether the vulnerable code is present and reachable. A CVSS score is a worst-case rating; it does not account for your specific deployment, configuration, or usage patterns. Kodem, an Intelligent Application Security platform, uses runtime intelligence to show which vulnerabilities actually execute in production, so you can focus on the ones that represent real risk. Get a demo
- What actually determines whether CVE-2026-65835 is exploitable, and how bad it is? Exploitability and impact are not fixed properties of a CVE. They depend on runtime truth: whether the vulnerable code is present, reachable, and actually executes in your application. A high CVSS score on a dependency that never runs is not the same as real risk. Kodem, an Intelligent Application Security platform, uses runtime intelligence to reveal which vulnerabilities actually execute in production, so teams prioritize the ones that genuinely matter.
- How do I fix CVE-2026-65835? Upgrade
github.com/projectcapsule/capsuleto 0.13.8 or later.