Skip to content
CVE IDCVE-2026-61794GitHub advisory IDGHSA-gxjc-74v5-3vx3

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.

Medium4.9Fix availableGitHub reviewed

Published 18 Sept 2026Updated 18 Sept 2026

4.9MediumCVSS 3.1
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.go
  • internal/webhook/namespace/validation/user_metadata.go
  • pkg/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

  1. Update a Tenant so that:
    • spec.namespaceOptions.forbiddenLabels.regex is valid
    • spec.namespaceOptions.forbiddenAnnotations.regex is malformed, for example: [invalid-regex(
  2. The Tenant update is accepted because the webhook compiles the labels regex for both fields.
  3. Create or update a Namespace that triggers forbidden metadata validation.
  4. 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:H

Medium4.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/capsule
    Go
    pkg:golang/github.com/projectcapsule/capsule
    Affected versions
    >= 0.13.0, < 0.13.7
    Fixed in
    0.13.7

Fix

Source: OSV (GitHub advisory)

Fix available

Upgrade to 0.13.7 or later.

Patch commits

  • 8d89d68Patch commitgithub.com/projectcapsule/capsule

    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
  • #1983Pull requestgithub.com/projectcapsule/capsule

Vulnerability intelligence

References

Credits

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.