{"id":"GO-2026-6157","revision":null,"records":[{"revision":"dfb7ee4b773a4cf5bb29197ab17e1747","observedAt":"2026-10-23T15:48:27.903+00:00","statement":{"source":"cve-program","id":"CVE-2026-65835","aliases":[],"title":"Capsule: Incomplete fix of CVE-2026-22872: TenantResource RawItems and Generators still allow cluster-scoped resource creation (cross-tenant privilege escalation)","description":"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.","state":0,"publishedAt":"2026-07-30T19:53:52.769+00:00","modifiedAt":"2026-07-31T19:17:25.535+00:00","affected":[{"ecosystem":"Vendor product","name":"capsule","ranges":[],"versions":[],"rawVersionEvidence":"{\n                    \"vendor\": \"projectcapsule\",\n                    \"product\": \"capsule\",\n                    \"versions\": [\n                        {\n                            \"version\": \">= 0.13.0, < 0.13.8\",\n                            \"status\": \"affected\"\n                        }\n                    ]\n                }"}],"metrics":[{"system":"CVSS 3.1","vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:L","score":6.6,"severity":"MEDIUM"}],"references":["https://github.com/projectcapsule/capsule/security/advisories/GHSA-jr6p-8pjj-mfx6","https://github.com/projectcapsule/capsule/releases/tag/v0.13.8"],"sourceUrl":"https://www.cve.org/CVERecord?id=CVE-2026-65835","license":"CVE Program Terms of Use","key":"cve-program:CVE-2026-65835","identifiers":["CVE-2026-65835"]},"retained":false,"historicalAffected":[]},{"revision":"a55e6c63449142c6b11a4f16f428c6ab","observedAt":"2026-10-25T15:18:45.851+00:00","statement":{"source":"nvd","id":"CVE-2026-65835","aliases":[],"title":"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 handleRa…","description":"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.","state":0,"publishedAt":"2026-07-30T20:18:13.267+00:00","modifiedAt":"2026-10-23T22:10:00.16+00:00","affected":[],"metrics":[{"system":"CVSS 3.1 · security-advisories@github.com · Secondary","vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:L","score":6.6,"severity":"MEDIUM"}],"references":["https://github.com/projectcapsule/capsule/releases/tag/v0.13.8","https://github.com/projectcapsule/capsule/security/advisories/GHSA-jr6p-8pjj-mfx6"],"sourceUrl":"https://nvd.nist.gov/vuln/detail/CVE-2026-65835","license":"NIST NVD usage terms; underlying source attribution retained","enrichment":{"sourceStatus":"Deferred","weaknesses":["CWE-269","CWE-863"],"productCriteria":[],"sourceDates":{"published":"2026-07-30T20:18:13.267","lastModified":"2026-10-23T22:10:00.160"},"relatedAdvisories":[],"note":"NVD analysis and CPE criteria are source context, not proof that a package or your environment is affected. Complete affected data, logical configurations and SSVC are retained in the original JSON."},"key":"nvd:CVE-2026-65835","identifiers":["CVE-2026-65835"]},"retained":false,"historicalAffected":[]},{"revision":"ef33b67756d44d7cb427ae121f63bdcf","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GHSA-jr6p-8pjj-mfx6","aliases":["CVE-2026-65835","GO-2026-6157"],"title":"Capsule has an incomplete fix of CVE-2026-22872: TenantResource RawItems and Generators still allow cluster-scoped resource creation (cross-tenant privilege escalation)","description":"### 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.)","state":0,"publishedAt":"2026-07-31T16:53:42+00:00","modifiedAt":"2026-08-18T15:10:37.2833294+00:00","affected":[{"ecosystem":"Go","name":"github.com/projectcapsule/capsule","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0.13.0"},{"kind":"fixed","version":"0.13.8"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[{"system":"CVSS_V3","vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:L/I:L/A:L","score":null,"severity":null},{"system":"Publisher rating","vector":null,"score":null,"severity":"MODERATE"}],"references":["https://github.com/projectcapsule/capsule/security/advisories/GHSA-jr6p-8pjj-mfx6","https://nvd.nist.gov/vuln/detail/CVE-2026-65835","https://github.com/projectcapsule/capsule","https://github.com/projectcapsule/capsule/releases/tag/v0.13.8"],"sourceUrl":"https://github.com/advisories/GHSA-jr6p-8pjj-mfx6","license":"GitHub Advisory Database · CC-BY-4.0","key":"osv:GHSA-jr6p-8pjj-mfx6","identifiers":["GHSA-jr6p-8pjj-mfx6","CVE-2026-65835","GO-2026-6157"]},"retained":false,"historicalAffected":[]},{"revision":"f5c37a3968154d93a169d1c23143be3d","observedAt":"2026-10-24T13:19:41.952+00:00","statement":{"source":"osv","id":"GO-2026-6157","aliases":["CVE-2026-65835","GHSA-jr6p-8pjj-mfx6"],"title":"Capsule has an incomplete fix of CVE-2026-22872: TenantResource RawItems and Generators still allow cluster-scoped resource creation (cross-tenant privilege escalation) in github.com/projectcapsule/capsule","description":"Capsule has an incomplete fix of CVE-2026-22872: TenantResource RawItems and Generators still allow cluster-scoped resource creation (cross-tenant privilege escalation) in github.com/projectcapsule/capsule","state":0,"publishedAt":"2026-08-18T14:32:29+00:00","modifiedAt":"2026-08-18T15:00:18.8989856+00:00","affected":[{"ecosystem":"Go","name":"github.com/projectcapsule/capsule","ranges":[{"type":"SEMVER","events":[{"kind":"introduced","version":"0.13.0"},{"kind":"fixed","version":"0.13.8"}]}],"versions":[],"rawVersionEvidence":null}],"metrics":[],"references":["https://github.com/projectcapsule/capsule/security/advisories/GHSA-jr6p-8pjj-mfx6","https://nvd.nist.gov/vuln/detail/CVE-2026-65835","https://github.com/projectcapsule/capsule/releases/tag/v0.13.8"],"sourceUrl":"https://osv.dev/vulnerability/GO-2026-6157","license":"OSV · upstream source license applies","key":"osv:GO-2026-6157","identifiers":["GO-2026-6157","CVE-2026-65835","GHSA-jr6p-8pjj-mfx6"]},"retained":false,"historicalAffected":[]}],"coverage":[{"source":"cisa-kev:global","scope":"Complete CISA KEV catalog; all vendors. Missing entries do not establish absence of exploitation.","generation":"2026-10-26T13:35:31.4084177+00:00","complete":true,"records":1756,"lastAttemptAt":"2026-10-26T13:35:31.4084177+00:00","lastSuccessAt":"2026-10-26T13:35:31.5775932+00:00","error":null,"lastVerifiedAt":"2026-10-26T13:35:31.5775972+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"cve-program","scope":"Official CVE Program baseline and cumulative hourly delta; all vendors, published and rejected records","generation":"cve-5ba1945314e042c2ced14b33f3680fa71692812d925544312b218f5eb8a26e71-e7962156c388e029d9e5dbbcda79fbd40ade61bdd41d51546adb4696b3e29228","complete":true,"records":414161,"lastAttemptAt":"2026-10-26T13:35:30.7074205+00:00","lastSuccessAt":"2026-10-26T11:36:10.2537359+00:00","error":null,"lastVerifiedAt":"2026-10-26T13:35:30.7074205+00:00","snapshotPublishedAt":"2026-10-26T11:28:55+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"euvd","scope":"Rolling EUVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global EUVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-43321610382942b8ad8c85917eab1546","complete":false,"records":4735,"lastAttemptAt":"2026-10-26T13:35:59.8295777+00:00","lastSuccessAt":"2026-10-24T23:18:49.862+00:00","error":"InvalidDataException","lastVerifiedAt":"2026-10-24T23:18:49.862+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":4564,"expectedIdentifiers":13477},{"source":"first-epss:nuget","scope":"FIRST EPSS for explicit CVE aliases in the collected public NuGet archive. Not a global EPSS backfill.","generation":"2026-10-26T13:35:31.4084177+00:00","complete":true,"records":1093,"lastAttemptAt":"2026-10-26T13:35:31.4084177+00:00","lastSuccessAt":"2026-10-26T13:35:31.5784069+00:00","error":null,"lastVerifiedAt":"2026-10-26T13:35:31.5784074+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"nvd","scope":"Rolling NVD lookups of CVE aliases in current public OSV archives; 500 identifiers per refresh, rechecked after 48 hours. Not a global NVD catalog. Successful not-found lookups count as checked; they do not imply withdrawal or safety. No reader inventory is sent.","generation":"enrichment-03a3ea3298bf4e3f8edd073e1229d545","complete":true,"records":13416,"lastAttemptAt":"2026-10-26T13:35:57.9513146+00:00","lastSuccessAt":"2026-10-26T13:35:57.948+00:00","error":null,"lastVerifiedAt":"2026-10-26T13:35:57.948+00:00","snapshotPublishedAt":null,"importing":false,"stagedRecords":0,"checkedIdentifiers":13477,"expectedIdentifiers":13477},{"source":"osv:Go","scope":"Complete OSV Go ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"go-2375a4e597279abf92e8747e140fe8da9d421877cd49cae3ac69a2cb78469b2c","complete":true,"records":9779,"lastAttemptAt":"2026-10-26T13:35:31.3462861+00:00","lastSuccessAt":"2026-10-24T13:19:53.1346702+00:00","error":null,"lastVerifiedAt":"2026-10-26T13:35:31.3462861+00:00","snapshotPublishedAt":"2026-10-24T03:03:12+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:NuGet","scope":"Complete OSV NuGet ecosystem archive, including GitHub Advisory Database records; NuGet version matching only","generation":"nuget-16ad89dfea13ab9e9b0108e63a759d63bd4559cc68b58491107d62ee35bbbaf2","complete":true,"records":1965,"lastAttemptAt":"2026-10-26T13:35:30.8546246+00:00","lastSuccessAt":"2026-10-23T16:01:26.4487605+00:00","error":null,"lastVerifiedAt":"2026-10-26T13:35:30.8546246+00:00","snapshotPublishedAt":"2026-10-21T12:18:07+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:crates.io","scope":"Complete OSV crates.io ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"crates.io-7d18ad8657bc2f95d55948e9e16b3c82a8ac06830df5ec8d356048b8420b72c3","complete":true,"records":2972,"lastAttemptAt":"2026-10-26T13:35:31.3609129+00:00","lastSuccessAt":"2026-10-26T11:36:23.0131888+00:00","error":null,"lastVerifiedAt":"2026-10-26T13:35:31.3609129+00:00","snapshotPublishedAt":"2026-10-26T11:33:16+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null},{"source":"osv:npm","scope":"Complete OSV npm ecosystem archive, including withdrawn and malicious-package source records; statement counts are not unique CVE counts","generation":"npm-690135177074a0c4b9ddcb48232cb870c32b1a7adcd972a81c224810b8437d0d","complete":true,"records":230805,"lastAttemptAt":"2026-10-26T13:35:31.2341103+00:00","lastSuccessAt":"2026-10-26T12:37:54.7648812+00:00","error":null,"lastVerifiedAt":"2026-10-26T13:35:31.2341103+00:00","snapshotPublishedAt":"2026-10-26T11:48:32+00:00","importing":false,"stagedRecords":0,"checkedIdentifiers":null,"expectedIdentifiers":null}]}