{"id":"CVE-2026-61794","aliases":["EUVD-2026-83055","GHSA-gxjc-74v5-3vx3","GO-2026-6521"],"status":"published","title":"Capsule: Malformed ForbiddenAnnotations.Regex can bypass Tenant validation and trigger namespace admission panic","description":"Capsule is a multi-tenancy and policy-based framework for Kubernetes. From 0.13.0 until 0.13.7, the Tenant update validation in internal/webhook/tenant/validation/forbidden_annotations_regex.go compiles ForbiddenLabels.Regex for both the labels and annotations checks instead of validating ForbiddenAnnotations.Regex. An administrator who can update a Tenant can therefore persist a malformed ForbiddenAnnotations.Regex while leaving the labels expression valid. Namespace creation or update later passes the stored expression through pkg/api/forbidden_list.go, where regexp.MustCompile can panic during forbidden metadata validation and deny namespace operations for the affected tenant. This issue is fixed in version 0.13.7.","severity":{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H","level":"medium","assessor":"cna","from":"cve"},"epss":{"day":"2026-11-11","score":0.00587,"percentile":0.48535,"model":"v2026.06.15"},"facts":{"in_kev":false,"known_exploited":false,"public_exploit":false,"fix_available":true},"cwes":["CWE-20"],"published":"2026-09-18T16:26:18Z","modified":"2026-10-28T02:30:29Z","fixes":[{"ecosystem":"Go","package":"github.com/projectcapsule/capsule","fixed_in":["0.13.7"],"sources":["ghsa","osv"]}],"affected":[{"source":"ghsa","ecosystem":"Go","package":"github.com/projectcapsule/capsule","ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0.13.0"},{"fixed":"0.13.7"}]}]},{"source":"osv","ecosystem":"Go","package":"github.com/projectcapsule/capsule","ranges":[{"type":"SEMVER","events":[{"introduced":"0.13.0"},{"fixed":"0.13.7"}]}]},{"source":"osv","ecosystem":"Go","package":"github.com/projectcapsule/capsule","ranges":[{"type":"SEMVER","events":[{"introduced":"0.13.0"},{"fixed":"0.13.7"}]}]}],"products":[{"vendor":"projectcapsule","product":"capsule"}],"references":[{"url":"https://github.com/projectcapsule/capsule/security/advisories/GHSA-gxjc-74v5-3vx3","tags":["x_refsource_CONFIRM","exploit","advisory","web"]},{"url":"https://github.com/projectcapsule/capsule/pull/1983","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/projectcapsule/capsule/commit/8d89d6865df6f41c7faa22fc9e807a57b01bfd0e","tags":["x_refsource_MISC","fix","web"]},{"url":"https://github.com/projectcapsule/capsule/releases/tag/v0.13.7","tags":["x_refsource_MISC","web"]},{"url":"https://github.com/advisories/GHSA-gxjc-74v5-3vx3"},{"url":"https://github.com/CVEProject/cvelistV5/tree/main/cves/2026/61xxx/CVE-2026-61794.json","tags":["advisory"]},{"url":"https://nvd.nist.gov/vuln/detail/CVE-2026-61794","tags":["advisory"]},{"url":"https://github.com/projectcapsule/capsule","tags":["package"]}],"sources":{"cve":[{"id":"CVE-2026-61794","title":"Capsule: Malformed ForbiddenAnnotations.Regex can bypass Tenant validation and trigger namespace admission panic","description":"Capsule is a multi-tenancy and policy-based framework for Kubernetes. From 0.13.0 until 0.13.7, the Tenant update validation in internal/webhook/tenant/validation/forbidden_annotations_regex.go compiles ForbiddenLabels.Regex for both the labels and annotations checks instead of validating ForbiddenAnnotations.Regex. An administrator who can update a Tenant can therefore persist a malformed ForbiddenAnnotations.Regex while leaving the labels expression valid. Namespace creation or update later passes the stored expression through pkg/api/forbidden_list.go, where regexp.MustCompile can panic during forbidden metadata validation and deny namespace operations for the affected tenant. This issue is fixed in version 0.13.7.","status":"published","published":"2026-09-18T16:26:18.669Z","modified":"2026-09-22T14:55:27.246Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H","level":"medium","assessor":"cna"}],"cwes":["CWE-20"],"updated_at":"2026-11-02T14:19:53.4444Z"}],"euvd":[{"id":"EUVD-2026-83055","description":"Capsule is a multi-tenancy and policy-based framework for Kubernetes. From 0.13.0 until 0.13.7, the Tenant update validation in internal/webhook/tenant/validation/forbidden_annotations_regex.go compiles ForbiddenLabels.Regex for both the labels and annotations checks instead of validating ForbiddenAnnotations.Regex. An administrator who can update a Tenant can therefore persist a malformed ForbiddenAnnotations.Regex while leaving the labels expression valid. Namespace creation or update later passes the stored expression through pkg/api/forbidden_list.go, where regexp.MustCompile can panic during forbidden metadata validation and deny namespace operations for the affected tenant. This issue is fixed in version 0.13.7.","status":"published","published":"2026-09-18T16:26:18Z","modified":"2026-09-22T14:55:27Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H","level":"medium"}],"updated_at":"2026-11-02T17:28:02.937716Z"}],"ghsa":[{"id":"GHSA-gxjc-74v5-3vx3","title":"Capsule: Malformed ForbiddenAnnotations.Regex can bypass Tenant validation and trigger namespace admission panic","description":"### Summary\nA validation bug in `internal/webhook/tenant/validation/forbidden_annotations_regex.go` allows an invalid `ForbiddenAnnotations.Regex` value to bypass Tenant admission on update. The webhook compiles `ForbiddenLabels.Regex` for both labels and annotations, so a malformed annotations regex can be persisted. Once stored, namespace admission later evaluates the bad regex through `pkg/api/forbidden_list.go`, where `regexp.MustCompile` can panic and cause admission failure.\n\n### Details\nIn `internal/webhook/tenant/validation/forbidden_annotations_regex.go`, `OnUpdate` validates the new Tenant object, but the loop compiles `tnt.Spec.NamespaceOptions.ForbiddenLabels.Regex` for both `labels` and `annotations`. That means an invalid `ForbiddenAnnotations.Regex` is never validated if `ForbiddenLabels.Regex` is valid.\n\nRelevant paths:\n- `internal/webhook/tenant/validation/forbidden_annotations_regex.go`\n- `internal/webhook/namespace/validation/user_metadata.go`\n- `pkg/api/forbidden_list.go`\n\nNamespace admission later calls `api.ValidateForbidden(...)`, and `ForbiddenListSpec.RegexMatch()` uses `regexp.MustCompile(in.Regex)`. If the malformed regex is present in the Tenant spec, any namespace request that reaches this check can panic or fail hard, causing denial of service for namespace operations in the affected tenant.\n\n\n### PoC\n1. Update a Tenant so that:\n   - `spec.namespaceOptions.forbiddenLabels.regex` is valid\n   - `spec.namespaceOptions.forbiddenAnnotations.regex` is malformed, for example: `[invalid-regex(`\n2. The Tenant update is accepted because the webhook compiles the labels regex for both fields.\n3. Create or update a Namespace that triggers forbidden metadata validation.\n4. The namespace admission path reaches `regexp.MustCompile(...)` and panics.\n\n```\npackage main\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n)\n\ntype ForbiddenListSpec struct {\n\tRegex string\n}\n\ntype NamespaceOptions struct {\n\tForbiddenLabels      ForbiddenListSpec\n\tForbiddenAnnotations ForbiddenListSpec\n}\n\ntype Tenant struct {\n\tNamespaceOptions *NamespaceOptions\n}\n\nfunc validateTenantUpdate(tnt *Tenant) error {\n\tif tnt.NamespaceOptions == nil {\n\t\treturn nil\n\t}\n\n\tannotationsToCheck := map[string]string{\n\t\t\"labels\":      tnt.NamespaceOptions.ForbiddenLabels.Regex,\n\t\t\"annotations\": tnt.NamespaceOptions.ForbiddenAnnotations.Regex,\n\t}\n\n\tfor scope, annotation := range annotationsToCheck {\n\t\tif _, err := regexp.Compile(tnt.NamespaceOptions.ForbiddenLabels.Regex); err != nil {\n\t\t\treturn fmt.Errorf(\"deny update: unable to compile %s regex for forbidden %s\", annotation, scope)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc validateForbidden(metadata map[string]string, forbidden ForbiddenListSpec) error {\n\tfor key := range metadata {\n\t\tif forbidden.Regex != \"\" {\n\t\t\tif regexp.MustCompile(forbidden.Regex).MatchString(key) {\n\t\t\t\treturn fmt.Errorf(\"forbidden key matched: %s\", key)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc main() {\n\toldTenant := \u0026Tenant{\n\t\tNamespaceOptions: \u0026NamespaceOptions{\n\t\t\tForbiddenLabels:      ForbiddenListSpec{Regex: `^[a-z0-9-]+$`},\n\t\t\tForbiddenAnnotations: ForbiddenListSpec{Regex: `^[a-z0-9-]+$`},\n\t\t},\n\t}\n\n\tnewTenant := \u0026Tenant{\n\t\tNamespaceOptions: \u0026NamespaceOptions{\n\t\t\tForbiddenLabels:      ForbiddenListSpec{Regex: `^[a-z0-9-]+$`},\n\t\t\tForbiddenAnnotations: ForbiddenListSpec{Regex: `[invalid-regex(`},\n\t\t},\n\t}\n\n\tfmt.Println(\"=== Update step ===\")\n\tif err := validateTenantUpdate(newTenant); err != nil {\n\t\tfmt.Printf(\"unexpected deny: %v\\n\", err)\n\t} else {\n\t\tfmt.Println(\"allowed: malformed ForbiddenAnnotations.Regex bypassed validation\")\n\t}\n\n\tfmt.Println()\n\tfmt.Println(\"=== Namespace step ===\")\n\t_ = oldTenant\n\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tfmt.Printf(\"panic reproduced from ValidateForbidden: %v\\n\", r)\n\t\t}\n\t}()\n\n\t_ = validateForbidden(map[string]string{\"example\": \"value\"}, ForbiddenListSpec{Regex: `[invalid-regex(`})\n\tfmt.Println(\"no panic, unexpected\")\n}\n```\nExpected output:\n\n```text\n=== Update step ===\nallowed: malformed ForbiddenAnnotations.Regex bypassed validation\n\n=== Namespace step ===\npanic reproduced from ValidateForbidden: regexp: Compile(`[invalid-regex(`): error parsing regexp: missing closing ]: `[invalid-regex(`\n```\n\n\n\n### Impact\nAn attacker who can update the Tenant configuration can persist a malformed `ForbiddenAnnotations.Regex` and cause namespace admission failures for the affected tenant. This can result in a tenant-scoped denial of service.","status":"published","published":"2026-09-18T17:14:26Z","modified":"2026-09-18T17:14:28Z","cvss":[{"version":"3.1","score":4.9,"vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H","level":"medium"}],"cwes":["CWE-20"],"updated_at":"2026-11-02T14:41:19.455935Z"}],"nvd":[{"id":"CVE-2026-61794","description":"Capsule is a multi-tenancy and policy-based framework for Kubernetes. From 0.13.0 until 0.13.7, the Tenant update validation in internal/webhook/tenant/validation/forbidden_annotations_regex.go compiles ForbiddenLabels.Regex for both the labels and annotations checks instead of validating ForbiddenAnnotations.Regex. An administrator who can update a Tenant can therefore persist a malformed ForbiddenAnnotations.Regex while leaving the labels expression valid. Namespace creation or update later passes the stored expression through pkg/api/forbidden_list.go, where regexp.MustCompile can panic during forbidden metadata validation and deny namespace operations for the affected tenant. This issue is fixed in version 0.13.7.","status":"published","published":"2026-09-18T17:16:58.7Z","modified":"2026-09-24T21:25:27.05Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H","level":"medium","assessor":"secondary"}],"cwes":["CWE-20"],"updated_at":"2026-11-02T14:12:49.70655Z"}],"osv":[{"id":"CVE-2026-61794","title":"Capsule: Malformed ForbiddenAnnotations.Regex can bypass Tenant validation and trigger namespace admission panic","description":"Capsule is a multi-tenancy and policy-based framework for Kubernetes. From 0.13.0 until 0.13.7, the Tenant update validation in internal/webhook/tenant/validation/forbidden_annotations_regex.go compiles ForbiddenLabels.Regex for both the labels and annotations checks instead of validating ForbiddenAnnotations.Regex. An administrator who can update a Tenant can therefore persist a malformed ForbiddenAnnotations.Regex while leaving the labels expression valid. Namespace creation or update later passes the stored expression through pkg/api/forbidden_list.go, where regexp.MustCompile can panic during forbidden metadata validation and deny namespace operations for the affected tenant. This issue is fixed in version 0.13.7.","status":"published","published":"2026-09-18T16:26:18.669Z","modified":"2026-10-28T02:30:29.166599151Z","cvss":[{"version":"3.1","score":6.8,"vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:C/C:N/I:N/A:H","level":"medium"}],"cwes":["CWE-20"],"updated_at":"2026-11-02T15:45:12.933503Z"},{"id":"GHSA-gxjc-74v5-3vx3","title":"Capsule: Malformed ForbiddenAnnotations.Regex can bypass Tenant validation and trigger namespace admission panic","description":"### Summary\nA validation bug in `internal/webhook/tenant/validation/forbidden_annotations_regex.go` allows an invalid `ForbiddenAnnotations.Regex` value to bypass Tenant admission on update. The webhook compiles `ForbiddenLabels.Regex` for both labels and annotations, so a malformed annotations regex can be persisted. Once stored, namespace admission later evaluates the bad regex through `pkg/api/forbidden_list.go`, where `regexp.MustCompile` can panic and cause admission failure.\n\n### Details\nIn `internal/webhook/tenant/validation/forbidden_annotations_regex.go`, `OnUpdate` validates the new Tenant object, but the loop compiles `tnt.Spec.NamespaceOptions.ForbiddenLabels.Regex` for both `labels` and `annotations`. That means an invalid `ForbiddenAnnotations.Regex` is never validated if `ForbiddenLabels.Regex` is valid.\n\nRelevant paths:\n- `internal/webhook/tenant/validation/forbidden_annotations_regex.go`\n- `internal/webhook/namespace/validation/user_metadata.go`\n- `pkg/api/forbidden_list.go`\n\nNamespace admission later calls `api.ValidateForbidden(...)`, and `ForbiddenListSpec.RegexMatch()` uses `regexp.MustCompile(in.Regex)`. If the malformed regex is present in the Tenant spec, any namespace request that reaches this check can panic or fail hard, causing denial of service for namespace operations in the affected tenant.\n\n\n### PoC\n1. Update a Tenant so that:\n   - `spec.namespaceOptions.forbiddenLabels.regex` is valid\n   - `spec.namespaceOptions.forbiddenAnnotations.regex` is malformed, for example: `[invalid-regex(`\n2. The Tenant update is accepted because the webhook compiles the labels regex for both fields.\n3. Create or update a Namespace that triggers forbidden metadata validation.\n4. The namespace admission path reaches `regexp.MustCompile(...)` and panics.\n\n```\npackage main\n\nimport (\n\t\"fmt\"\n\t\"regexp\"\n)\n\ntype ForbiddenListSpec struct {\n\tRegex string\n}\n\ntype NamespaceOptions struct {\n\tForbiddenLabels      ForbiddenListSpec\n\tForbiddenAnnotations ForbiddenListSpec\n}\n\ntype Tenant struct {\n\tNamespaceOptions *NamespaceOptions\n}\n\nfunc validateTenantUpdate(tnt *Tenant) error {\n\tif tnt.NamespaceOptions == nil {\n\t\treturn nil\n\t}\n\n\tannotationsToCheck := map[string]string{\n\t\t\"labels\":      tnt.NamespaceOptions.ForbiddenLabels.Regex,\n\t\t\"annotations\": tnt.NamespaceOptions.ForbiddenAnnotations.Regex,\n\t}\n\n\tfor scope, annotation := range annotationsToCheck {\n\t\tif _, err := regexp.Compile(tnt.NamespaceOptions.ForbiddenLabels.Regex); err != nil {\n\t\t\treturn fmt.Errorf(\"deny update: unable to compile %s regex for forbidden %s\", annotation, scope)\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc validateForbidden(metadata map[string]string, forbidden ForbiddenListSpec) error {\n\tfor key := range metadata {\n\t\tif forbidden.Regex != \"\" {\n\t\t\tif regexp.MustCompile(forbidden.Regex).MatchString(key) {\n\t\t\t\treturn fmt.Errorf(\"forbidden key matched: %s\", key)\n\t\t\t}\n\t\t}\n\t}\n\n\treturn nil\n}\n\nfunc main() {\n\toldTenant := \u0026Tenant{\n\t\tNamespaceOptions: \u0026NamespaceOptions{\n\t\t\tForbiddenLabels:      ForbiddenListSpec{Regex: `^[a-z0-9-]+$`},\n\t\t\tForbiddenAnnotations: ForbiddenListSpec{Regex: `^[a-z0-9-]+$`},\n\t\t},\n\t}\n\n\tnewTenant := \u0026Tenant{\n\t\tNamespaceOptions: \u0026NamespaceOptions{\n\t\t\tForbiddenLabels:      ForbiddenListSpec{Regex: `^[a-z0-9-]+$`},\n\t\t\tForbiddenAnnotations: ForbiddenListSpec{Regex: `[invalid-regex(`},\n\t\t},\n\t}\n\n\tfmt.Println(\"=== Update step ===\")\n\tif err := validateTenantUpdate(newTenant); err != nil {\n\t\tfmt.Printf(\"unexpected deny: %v\\n\", err)\n\t} else {\n\t\tfmt.Println(\"allowed: malformed ForbiddenAnnotations.Regex bypassed validation\")\n\t}\n\n\tfmt.Println()\n\tfmt.Println(\"=== Namespace step ===\")\n\t_ = oldTenant\n\n\tdefer func() {\n\t\tif r := recover(); r != nil {\n\t\t\tfmt.Printf(\"panic reproduced from ValidateForbidden: %v\\n\", r)\n\t\t}\n\t}()\n\n\t_ = validateForbidden(map[string]string{\"example\": \"value\"}, ForbiddenListSpec{Regex: `[invalid-regex(`})\n\tfmt.Println(\"no panic, unexpected\")\n}\n```\nExpected output:\n\n```text\n=== Update step ===\nallowed: malformed ForbiddenAnnotations.Regex bypassed validation\n\n=== Namespace step ===\npanic reproduced from ValidateForbidden: regexp: Compile(`[invalid-regex(`): error parsing regexp: missing closing ]: `[invalid-regex(`\n```\n\n\n\n### Impact\nAn attacker who can update the Tenant configuration can persist a malformed `ForbiddenAnnotations.Regex` and cause namespace admission failures for the affected tenant. This can result in a tenant-scoped denial of service.","status":"published","published":"2026-09-18T17:14:26Z","modified":"2026-09-28T17:11:19.835452014Z","cvss":[{"version":"3.1","score":4.9,"vector":"CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H","level":"medium"}],"cwes":["CWE-20"],"updated_at":"2026-11-02T15:46:48.546324Z"},{"id":"GO-2026-6521","title":"Capsule: Malformed ForbiddenAnnotations.Regex can bypass Tenant validation and trigger namespace admission panic in github.com/projectcapsule/capsule","description":"Capsule: Malformed ForbiddenAnnotations.Regex can bypass Tenant validation and trigger namespace admission panic in github.com/projectcapsule/capsule","status":"published","published":"2026-09-28T16:43:40Z","modified":"2026-09-28T17:00:17.3532468Z","updated_at":"2026-11-02T15:47:03.11707Z"}]}}
