CVE-2026-65835: Github.com/projectcapsule/capsule Remote Code Execution Vulnerability

MODERATE
Advisory Identifier: GHSA-jr6p-8pjj-mfx6
CVSS 6.6
CWE-269 CWE-863
Published
Advisory Summary

CVE-2026-65835 is a MODERATE (CVSS 6.6) remote code execution vulnerability (CWE-269: Improper Privilege Management) affecting Github.com/projectcapsule/capsule libraries in the Go ecosystem. The issue involves tenantresource rawitems and generators still allow cluster-scoped resource creation (cross-tenant privilege escalation). Remediation is available by upgrading affected packages to version 0.13.8.

CVE-2026-65835 at a Glance

CVE Identifier CVE-2026-65835
GHSA Identifier GHSA-jr6p-8pjj-mfx6
Severity MODERATE
CVSS v3.1 Base Score 6.6
CWE Classification CWE-269: Improper Privilege Management
Affected Product Github.com/projectcapsule/capsule
Package Ecosystem Go
Published Date
Last Updated

Security Impact

CVSS: 6.6

The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:L).

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required High (PR:H)
User Interaction None (UI:N)
Scope Changed (S:C)
Confidentiality Low (C:L)
Integrity Low (I:L)
Availability Low (A:L)

How to Fix CVE-2026-65835

To remediate this vulnerability, upgrade all affected Github.com/projectcapsule/capsule dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/projectcapsule/capsule fixed: 0.13.8
Upgrade github.com/projectcapsule/capsule to 0.13.8
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/projectcapsule/capsule

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-65835, inspect your project dependencies for Github.com/projectcapsule/capsule:

inspect dependencies for github.com/projectcapsule/capsule

Analyze the terminal output to locate any version of Github.com/projectcapsule/capsule in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.13.8), your application is affected.

Note: Verify declared build manifests and deployed runtime container environments.

Technical Details

Vulnerability Mechanism & Technical Analysis

This vulnerability is classified under CWE-269: Improper Privilege Management, where the product does not properly assign, modify, track, or check privileges for an actor, creating an unintended sphere of control for that actor. In Github.com/projectcapsule/capsule, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.

Source Advisory Statement

### 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 `SetNamespace`s 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: ```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 (`incompletefix_poc_test.go`), run against trunk HEAD with go1.26.4, proves the asymmetry: - `TestRawItemPath_NoClusterScopeGuard`: feeds a `ClusterRole` rawItem to `handleRawItem` -> object returned unchanged, no rejection (PASS). - `TestNamespacedItemsPath_HasClusterScopeGuard`: 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.)

CVE-2026-65835 Affected Github.com/projectcapsule/capsule Versions

1 component(s)
Fixed Versions:
0.13.8
Product / Package Ecosystem Affected Versions Fixed Version
github.com/projectcapsule/capsule
Go
≥ 0.13.0
< 0.13.8
0.13.8

References

Frequently Asked Questions

What is CVE-2026-65835?
CVE-2026-65835 is a security vulnerability in Github.com/projectcapsule/capsule involving TenantResource RawItems and Generators still allow cluster-scoped resource creation (cross-tenant privilege escalation) under CWE-269: Improper Privilege Management.
Which Github.com/projectcapsule/capsule versions are affected?
Affected versions include releases prior to 0.13.8 across affected packages: github.com/projectcapsule/capsule.
What version fixes CVE-2026-65835?
Upgrading to 0.13.8 (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/projectcapsule/capsule affected?
Yes, github.com/projectcapsule/capsule is affected in releases prior to 0.13.8. Upgrade your dependency to 0.13.8 or later.
What is the CVSS score of CVE-2026-65835?
CVE-2026-65835 has a CVSS v3.1 base score of 6.6 (MODERATE) with vector string CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:L.
What CWE is associated with CVE-2026-65835?
CVE-2026-65835 is classified under CWE-269: Improper Privilege Management (The product does not properly assign, modify, track, or check privileges for an actor, creating an unintended sphere of control for that actor.).
How can I check Go dependencies for CVE-2026-65835?
Run the dependency tree command: 'inspect dependencies for github.com/projectcapsule/capsule'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-jr6p-8pjj-mfx6",
  "modified" : "2026-07-31T16:53:42Z",
  "published" : "2026-07-31T16:53:42Z",
  "aliases" : [ "CVE-2026-65835" ],
  "summary" : "Capsule has an incomplete fix of CVE-2026-22872: TenantResource RawItems and Generators still allow cluster-scoped resource creation (cross-tenant privilege escalation)",
  "details" : "### Summary\nCVE-2026-22872 (GHSA-qjjm-7j9w-pw72) reported that a Tenant Owner could create cluster-scoped resources\n(e.g. `ClusterRole`, `ValidatingWebhookConfiguration`) through a `TenantResource`, because the controller\napplies them with its cluster-admin ServiceAccount and `SetNamespace` is ineffective for cluster-scoped\nkinds. The v0.13.0 fix added a cluster-scope rejection guard, but **only on the NamespacedItems selection\npath** (`ResourceReference.LoadResources` -> `IsNamespacedGVK`, error `\"cluster-scoped kind ... is not\nallowed\"`). The **RawItems create path — the exact vector the original advisory named — and the Generators\npath were not given this guard.** The vulnerability therefore persists in all releases **v0.13.0 through\nv0.13.7** and on trunk HEAD (`8d89d6865d`).\n\n### Details\nTenantResource reconcile flow:\n- `internal/controllers/resources/namespaced.go` `reconcile()` obtains the apply client via `loadClient()`;\n  by default (impersonation off, no `Spec.ServiceAccount`) this is the manager client whose SA is bound to\n  cluster-admin (`charts/capsule/templates/rbac.yaml:488-501`, `{fullname}-manager-rolebinding` ->\n  roleRef cluster-admin).\n- `Collector.Collect()` (`collect.go`) processes `spec.RawItems` via `handleRawItem` and `spec.Generators`\n  via `handleGeneratorItem`.\n\n`handleRawItem` (`collect.go:406-425`, trunk HEAD — byte-identical to v0.13.0):\n```go\ntmplString := tpl.FastTemplate(string(item.Raw), opts.Iterator.FastContext)\nobj := &unstructured.Unstructured{}\nunstructured.UnstructuredJSONScheme.Decode([]byte(tmplString), nil, obj)\nif ns != nil { obj.SetNamespace(ns.Name) }   // ONLY mitigation\nreturn obj, nil                                // NO IsNamespacedGVK / allowClusterScoped guard\n```\n`handleGeneratorItem` (`collect.go:382-404`) is the same: it only `SetNamespace`s on rendered objects.\n\nThe accumulated objects flow to `pkg/api/processor/processor_func.go` `Reconcile()` -> `Apply()` ->\n`clt.PatchApply(ctx, c, obj, ...)` (line 167/378) with **no scope check at any point**.\n\nBy contrast, `CollectNamespacedItems` (`collect.go:308`) calls `item.LoadResources(..., allowClusterScoped=false)`,\nand `pkg/template/reference.go:105-107` enforces:\n```go\nif !allowClusterScoped && !isNamespaced {\n    return nil, fmt.Errorf(\"cluster-scoped kind %s/%s is not allowed\", ...)\n}\n```\nSo the guard the fix added is real, but it sits on a different (selection) path than the one the CVE\ndescribed (RawItems create path). For cluster-scoped kinds, `SetNamespace` is ignored by the Kubernetes API\nserver, so the object is created cluster-wide by the cluster-admin client.\n\n**Parent-fix diff confirmation:** in v0.12.4 the RawItems handler in `processor.go` was the vulnerable code\n(`obj.SetNamespace(ns.Name)` then `createOrUpdate` via `r.client`). v0.13.0 refactored this into\n`collect.go` `handleRawItem` but left it without the new guard.\n\n### Proof of Concept\nA self-contained in-process Go test (`incompletefix_poc_test.go`), run against trunk HEAD with go1.26.4,\nproves the asymmetry:\n- `TestRawItemPath_NoClusterScopeGuard`: feeds a `ClusterRole` rawItem to `handleRawItem` -> object returned\n  unchanged, no rejection (PASS).\n- `TestNamespacedItemsPath_HasClusterScopeGuard`: feeds the same `ClusterRole` kind to\n  `LoadResources(allowClusterScoped=false)` -> rejected with\n  `\"cluster-scoped kind rbac.authorization.k8s.io/v1/ClusterRole is not allowed\"` (PASS).\n\n```\nVULNERABLE: RawItems path accepted cluster-scoped rbac.authorization.k8s.io/v1/ClusterRole;\n            metadata.namespace=\"tenant-ns\" (ignored by API server for cluster-scoped kinds)\nGUARDED:    NamespacedItems path correctly rejected cluster-scoped kind:\n            cluster-scoped kind rbac.authorization.k8s.io/v1/ClusterRole is not allowed\n```\n\nEnd-to-end (cluster) reproduction:\n1. Deploy capsule (default Helm) with `rbac.resources.create=true` (the opt-in that exposes TenantResources\n   to tenant owners; the configuration the original CVE applies to).\n2. As a Tenant Owner, create in a tenant namespace:\n   ```yaml\n   apiVersion: capsule.clastix.io/v1beta2\n   kind: TenantResource\n   metadata: {name: pwn, namespace: <tenant-ns>}\n   spec:\n     resources:\n       - namespaceSelector: {matchLabels: {capsule.clastix.io/tenant: <tenant>}}\n         rawItems:\n           - apiVersion: rbac.authorization.k8s.io/v1\n             kind: ClusterRole\n             metadata: {name: tenant-escalation}\n             rules: [{apiGroups: [\"*\"], resources: [\"*\"], verbs: [\"*\"]}]\n   ```\n3. Observe the cluster-scoped ClusterRole `tenant-escalation` is created by the cluster-admin controller,\n   despite the tenant owner lacking cluster RBAC to create it. Swap in `ValidatingWebhookConfiguration`\n   to intercept/exfiltrate cluster-wide Secrets.\n\n### Impact\nA Tenant Owner (namespace-scoped) escalates to cluster-admin-equivalent privileges and can compromise all\ntenants and the cluster control plane. Identical impact to CVE-2026-22872; the v0.13.0 remediation does not\nclose the RawItems/Generators vector.\n\n### Remediation\nApply the same `IsNamespacedGVK` / `allowClusterScoped` rejection inside `handleRawItem` and\n`handleGeneratorItem` — or centrally in `Collector.AddToAccumulation` / `processor.Apply` — so the create\npath enforces the same cluster-scope policy as the selection path. (`GlobalTenantResource` shares the path\nbut is not a privesc — cluster-admin-only to create.)",
  "severity" : [ {
    "type" : "CVSS_V3",
    "score" : "CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:L"
  } ],
  "affected" : [ {
    "package" : {
      "ecosystem" : "Go",
      "name" : "github.com/projectcapsule/capsule"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "0.13.0"
      }, {
        "fixed" : "0.13.8"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 0.13.7"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/projectcapsule/capsule/security/advisories/GHSA-jr6p-8pjj-mfx6"
  }, {
    "type" : "ADVISORY",
    "url" : "https://nvd.nist.gov/vuln/detail/CVE-2026-65835"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/projectcapsule/capsule"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/projectcapsule/capsule/releases/tag/v0.13.8"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-269", "CWE-863" ],
    "severity" : "MODERATE",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-07-31T16:53:42Z",
    "nvd_published_at" : "2026-07-30T20:18:13Z"
  }
}