high

CVE

CVE-2026-62290, CVE-2026-119115, CVE-2026-118758, CVE-2026-118759, CVE-2026-118760, CVE-2026-118761, CVE-2026-119127, CVE-2026-119128, CVE-2026-119129, CVE-2026-9800

CWE

CWE-863, CWE-287, CWE-22, CWE-409, CWE-347, CWE-640

Affected Surface

  • Kubernetes `cert-manager` (`github.com/cert-manager/cert-manager`) versions `>= 1.18.0, < 1.19.6` and `>= 1.20.0-alpha.0, < 1.20.3` (`CVE-2026-62290` / `GHSA-8rvj-mm4h-c258`, CVSS 7.3 High)
  • AWS Private CA Connector for Kubernetes (`github.com/cert-manager/aws-privateca-issuer`) versions `< 1.10.1` (`CVE-2026-119115` / `GHSA-hjrh-q6pg-mh82` / `AWS-2026-156`, CVSS 8.5 High)
  • Kubeflow Pipelines (`github.com/kubeflow/pipelines`) versions `< 2.18.0` (`CVE-2026-118758`, `CVE-2026-118759`, `CVE-2026-118761`, CVSS 7.5 High) and `>= 0.5.1, < 2.17.0` (`CVE-2026-118760`, CVSS 6.5 Medium)
  • ZITADEL (`github.com/zitadel/zitadel` Login V2) versions `>= 4.0.0, < 4.19.5` (`CVE-2026-119127`, `CVE-2026-119128`) and `>= 3.0.0, <= 3.4.15` / `>= 4.0.0, < 4.19.5` (`CVE-2026-119129`, CVSS 8.1 High)
  • Keycloak (`org.keycloak:keycloak-services < 26.6.4` and `org.keycloak:keycloak-policy-enforcer < 26.0.10`, `CVE-2026-9800` / `GHSA-f5p5-6xmx-p252`, CVSS 8.1 High)

TL;DR

On 29 October 2026, ten high-severity vulnerabilities were disclosed across Kubernetes certificate controllers, ML pipeline servers, and OIDC/IAM platforms:

  1. Kubernetes cert-manager (CVE-2026-62290 / GHSA-8rvj-mm4h-c258, CVSS 7.3 High, fixed in 1.19.6 and 1.20.3) and aws-privateca-issuer (CVE-2026-119115 / GHSA-hjrh-q6pg-mh82 / AWS-2026-156, CVSS 8.5 High, fixed in 1.10.1):
    • In cert-manager, the default cert-manager-edit aggregate ClusterRole granted namespace users create permission on challenges.acme.cert-manager.io, and ValidateChallenge() did not verify that a Challenge was owned by a cert-manager Order. A tenant could create a standalone Challenge referencing a ClusterIssuer with an attacker-controlled Challenge.spec.solver, bypassing dnsZones / dnsNames solver selectors and forcing cert-manager to send ClusterIssuer acme-dns credentials (X-Api-User and X-Api-Key) to an attacker’s host or mutate unauthorized DNS zones.
    • In aws-privateca-issuer (< 1.10.1), util.GetIssuer() looked up a namespaced AWSPCAIssuer first and, whenever that lookup returned an error, fell back to fetching a cluster-scoped AWSPCAClusterIssuer of the same name regardless of issuerRef.kind. A tenant whose CertificateRequest approval policy only allowed namespaced AWSPCAIssuer objects could name a ClusterIssuer under kind: AWSPCAIssuer and obtain certificates (including subordinate CA certificates) from the cluster-wide AWS Private CA.
  2. Kubeflow Pipelines < 2.18.0 (CVE-2026-118758, CVE-2026-118759, CVE-2026-118760, and CVE-2026-118761, CVSS 7.5 High): Four flaws in the Kubeflow Pipelines API server and frontend allowed callers to traverse outside mounted volumes on GET /artifacts/get?source=volume (CVE-2026-118758), read logs of arbitrary pods in a run’s namespace via GET /apis/v1alpha1/runs/{run_id}/nodes/{node_id}/log without readLog authorization or pipeline/runid pod-label checks (CVE-2026-118759), bypass multi-user namespace checks on frontend artifact routes (CVE-2026-118760), and crash the API server or persistence agent with pre-auth ZIP or PAX-header tar bombs (CVE-2026-118761).
  3. ZITADEL Login V2 < 4.19.5 (CVE-2026-119127, CVE-2026-119128, and CVE-2026-119129, CVSS 8.1 High / v4.0 up to 9.1 Critical) and Keycloak < 26.6.4 / < 26.0.10 (CVE-2026-9800 / GHSA-f5p5-6xmx-p252, CVSS 8.1 High): ZITADEL Login V2 computed its verificationCheck cookie as an unsalted sha256(userId:fingerprintId) hash that an unauthenticated attacker could forge offline (CVE-2026-119128), silently dropped malformed X-Zitadel-Public-Host headers to bypass the trusted-domain check and poison password-reset emails (CVE-2026-119127), and auto-approved OAuth 2.0 device authorizations as soon as a signed-in user visited /signedin (CVE-2026-119129). In Keycloak, Policy Enforcer compared request URIs against the configured access-denied-path using an unanchored match, allowing any authenticated user to bypass all role, scope, and UMA policies by embedding the access-denied path segment or query string in the target URL (CVE-2026-9800).

What to do now: Upgrade cert-manager to >= 1.20.3 or >= 1.19.6, aws-privateca-issuer to >= 1.10.1 (v1.10.1-eksbuild.1 on EKS), Kubeflow Pipelines to >= 2.18.0, ZITADEL to >= 4.19.5 (and configure a 32+ character ZITADEL_SESSION_COOKIE_SECRET), and keycloak-services / keycloak-policy-enforcer to >= 26.6.4 / >= 26.0.10.

Affected packages and projects

EcosystemPackage / ComponentCVE / AdvisorySeverityAffected versionsFixed version(s)Vulnerable path
Go / Helmgithub.com/cert-manager/cert-managerCVE-2026-62290 (GHSA-8rvj-mm4h-c258)CVSS 7.3 High>= 1.18.0, < 1.19.6; >= 1.20.0-alpha.0, < 1.20.31.19.6, 1.20.3deploy/charts/cert-manager/templates/rbac.yaml, pkg/issuer/acme/dns/dns.go
Go / Helmgithub.com/cert-manager/aws-privateca-issuerCVE-2026-119115 (GHSA-hjrh-q6pg-mh82, AWS-2026-156)CVSS 8.5 High< 1.10.11.10.1 (v1.10.1-eksbuild.1)pkg/controllers/certificaterequest_controller.go, pkg/util/issuers.go (GetIssuer)
Go / Node.jsgithub.com/kubeflow/pipelinesCVE-2026-118758 (GHSA-2fg9-fx2f-439r), CVE-2026-118759 (GHSA-wg5q-x4j9-qm54), CVE-2026-118761 (GHSA-8fmv-6rg5-5924), CVE-2026-118760 (GHSA-vjhf-6c8f-qhwj)CVSS 7.5 High / 6.5 Medium< 2.18.0 (118760 fixed in 2.17.0)2.18.0frontend/server/handlers/artifacts.ts, backend/src/apiserver/resource/resource_manager.go (ReadLog), server/util.go
Go / Next.jsgithub.com/zitadel/zitadel (Login V2)CVE-2026-119127 (GHSA-mchc-246r-6m76), CVE-2026-119128 (GHSA-84fg-x5h4-w8xv), CVE-2026-119129 (GHSA-qj3q-235g-qr6w)CVSS 8.1 / 7.4 High (v4.0 up to 9.1 Critical)>= 4.0.0, < 4.19.5 (119129 also affects 3.0.0..3.4.15)4.19.5internal/api/http/middleware/origin_interceptor.go, apps/login/src/lib/verification-check.ts, apps/login/src/app/(login)/device/consent/page.tsx
Mavenorg.keycloak:keycloak-services, org.keycloak:keycloak-policy-enforcerCVE-2026-9800 (GHSA-f5p5-6xmx-p252)CVSS 8.1 Highkeycloak-services < 26.6.4, keycloak-policy-enforcer < 26.0.1026.6.4, 26.0.10Keycloak Policy Enforcer URI comparison (access-denied-path check)

Technical analysis

1. cert-manager (CVE-2026-62290) and aws-privateca-issuer (CVE-2026-119115): cross-scope ClusterIssuer abuse

In cert-manager, normal ACME certificate issuance flows from a Certificate to an Order, where the Order controller evaluates the referenced Issuer or ClusterIssuer’s solvers[].selector rules (dnsZones, dnsNames, matchLabels) and copies the chosen solver config into a child Challenge resource (acme.cert-manager.io/v1).

However, two things were true in cert-manager 1.18.0 through 1.19.5 and 1.20.0 through 1.20.2:

  1. The Helm chart’s cert-manager-edit aggregate ClusterRole (granted by default to namespace admin and edit roles) included verbs: ["create", "delete", "deletecollection", "patch", "update"] on challenges.acme.cert-manager.io.
  2. When reconciling a Challenge, pkg/issuer/acme/dns/dns.go loaded credentials from the ClusterIssuer resource namespace (cert-manager) or ambient cloud credentials whenever challenge.Spec.IssuerRef.Kind == "ClusterIssuer", but read the DNS01 provider configuration from challenge.Spec.Solver on the untrusted Challenge object itself.

A tenant service account with challenges create permission in any namespace could apply a standalone Challenge referencing ClusterIssuer/cluster-prod while setting spec.solver.dns01.acmeDNS.host: https://attacker[.]example/acmedns and accountSecretRef.name: cluster-acmedns-account. When the Challenge controller called Present(), it loaded cluster-acmedns-account from the cert-manager namespace and sent the secret’s X-Api-User and X-Api-Key headers to attacker[.]example (commit 6bda47297c removes create on challenges and create/patch/update on orders from the aggregate ClusterRole).

In aws-privateca-issuer (< 1.10.1, CVE-2026-119115), GetIssuer() in pkg/util/issuers.go ignored cr.Spec.IssuerRef.Kind whenever a namespaced lookup failed:

--- a/pkg/util/issuers.go
+++ b/pkg/util/issuers.go
@@ -29,22 +30,38 @@ var realtimeClock clock.Clock = clock.RealClock{}
-// GetIssuer returns either an AWSPCAClusterIssuer or AWSPCAIssuer by its name
-func GetIssuer(ctx context.Context, client client.Client, name types.NamespacedName) (api.GenericIssuer, error) {
-	iss := new(api.AWSPCAIssuer)
-	err := client.Get(ctx, name, iss)
-	if err != nil {
-		ciss := new(api.AWSPCAClusterIssuer)
-		cname := types.NamespacedName{
-			Name: name.Name,
-		}
-		err = client.Get(ctx, cname, ciss)

In pkg/controllers/certificaterequest_controller.go, issuerName.Namespace was cleared only when cr.Spec.IssuerRef.Kind == "AWSPCAClusterIssuer", so passing kind: AWSPCAIssuer (or kind: Issuer) with name: prod-root-ca caused client.Get(ctx, {Namespace: "tenant", Name: "prod-root-ca"}, iss) to return NotFound and immediately fall through to fetching the cluster-wide AWSPCAClusterIssuer prod-root-ca. Because RBAC and cert-manager CertificateRequestPolicy / approver rules commonly allow tenants to approve requests referencing namespaced AWSPCAIssuer objects while restricting AWSPCAClusterIssuer, a tenant could bypass approval policy and mint certificates from the cluster-scoped AWS Private CA. Commit 9ae225b695 (v1.10.1) requires issuerRef.kind to be AWSPCAIssuer or AWSPCAClusterIssuer and queries only that exact resource kind.

2. Kubeflow Pipelines 2.18.0 (CVE-2026-118758, CVE-2026-118759, CVE-2026-118760, and CVE-2026-118761)

Kubeflow Pipelines 2.18.0 patches four vulnerabilities across its TypeScript frontend proxy and Go API server:

  • Volume artifact path traversal (CVE-2026-118758, commit 4d9bc5ab12): In frontend/server/handlers/artifacts.ts, GET /artifacts/get?source=volume&bucket=<pvc>&key=<path> resolved the file path without confining it to the mounted PVC root, and domain_from_url() in domain-checker.ts used a regex (match(/^(?:https?:\/\/)?(?:[^@/\n]+@)?([^:/?\n]+)/)) that accepted file:///etc/passwd when the domain allowlist was ^.*$. Version 2.18.0 opens volume artifacts via openFileWithinRoot() and parses URLs with new URL() restricting schemes to http: and https:.
  • Cross-pod log disclosure via ReadRunLogV1 (CVE-2026-118759, commit be4723e337): In backend/src/apiserver/resource/resource_manager.go, ReadLog(ctx, runId, nodeId, follow, dst) looked up the namespace of runId and then streamed logs from the pod named nodeId in that namespace without authorizing the caller against runId or checking whether the pod nodeId actually belonged to runId:
    --- a/backend/src/apiserver/resource/resource_manager.go
    +++ b/backend/src/apiserver/resource/resource_manager.go
    @@ -1505,6 +1505,15 @@ func (r *ResourceManager) ReadLog(ctx context.Context, runId string, nodeId stri
    -func (r *ResourceManager) readRunLogFromPod(ctx context.Context, namespace string, nodeId string, follow bool, dst io.Writer) error {
    +func (r *ResourceManager) readRunLogFromPod(ctx context.Context, runID string, namespace string, nodeID string, follow bool, dst io.Writer) error {
    +	// The caller controls nodeID, so confirm the pod was created by this run
    +	// before streaming, otherwise the run only selects a namespace and any pod
    +	// in it could be read with the API server's credentials.
    +	pod, err := r.k8sCoreClient.PodClient(namespace).Get(ctx, nodeID, v1.GetOptions{})
    Version 2.18.0 authorizes a dedicated readLog RBAC verb and verifies that the pod’s pipeline/runid label matches runID before streaming.
  • Pre-auth ZIP and PAX-header tar bomb OOM (CVE-2026-118761, commits 1121d9a081 and ba9ae72cc8): Multipart pipeline uploads decompressed .zip and .tar.gz archives into memory before running namespace authorization, and tar.Reader.Next() decompressed unbounded PAX extended headers (TypeXHeader) before reaching the per-file size check. Version 2.18.0 wraps both gzipReader and entry readers in io.LimitedReader with an overflow-safe ArchiveTraversalBudget(int64(maxFileLength)) + 1 sentinel.

3. ZITADEL 4.19.5 (CVE-2026-119127, CVE-2026-119128, CVE-2026-119129) and Keycloak 26.6.4 (CVE-2026-9800)

In ZITADEL (4.0.0 before 4.19.5), three flaws affected the Next.js Login V2 application and Go origin interceptor:

  1. Forgeable verificationCheck and linkFingerprint cookies (CVE-2026-119128 / GHSA-84fg-x5h4-w8xv, commit e32ba7aa69): After a user verified an email or invite code, Login V2 set a verificationCheck cookie equal to sha256(userId:fingerprintId) (and used sha256(sessionId + fingerprintId) for IdP account linking). Because both userId and the client-side fingerprintId cookie were known to the client without any server secret, an unauthenticated attacker could compute sha256(victimUserId:attackerFingerprint) offline, skip the email/invite verification step for any user without an enrolled authentication factor, and register their own password or passkey on the account. Version 4.19.5 replaces the raw SHA-256 digest with a 5-minute HMAC proof (createSignedProof) keyed via HKDF from ZITADEL_SESSION_COOKIE_SECRET.
  2. Public-host header sanitization fallback bypass (CVE-2026-119127 / GHSA-mchc-246r-6m76, commit 6493aa908c): In internal/api/http/middleware/origin_interceptor.go, composeDomainContext() extracted publicHost from X-Zitadel-Public-Host / X-Forwarded-Host. If the header contained a trailing slash or userinfo (such as X-Zitadel-Public-Host: evil[.]com:443/), hostFromRequest() returned publicHost = "", which caused ZITADEL to skip the TrustedDomains check while Login V2 still used the raw header to construct password-reset and invite links:
    --- a/internal/api/http/middleware/origin_interceptor.go
    +++ b/internal/api/http/middleware/origin_interceptor.go
    @@ -30,11 +30,17 @@ func composeDomainContext(r *http.Request, enforceHttps bool, instanceDomainHead
    -	instanceHost, instanceProto := hostFromRequest(r, instanceDomainHeaders)
    -	publicHost, publicProto := hostFromRequest(r, publicDomainHeaders)
    +	instanceHost, instanceProto, _ := hostFromRequest(r, instanceDomainHeaders)
    +	publicHost, publicProto, rawPublicHost := hostFromRequest(r, publicDomainHeaders)
     	if instanceHost == "" {
     		instanceHost = r.Host
     	}
    +	if publicHost == "" && rawPublicHost != "" {
    +		publicHost = rawPublicHost
    +	}
  3. Consent-less OAuth 2.0 Device Authorization approval (CVE-2026-119129 / GHSA-qj3q-235g-qr6w, commit a618740b57): Navigating a signed-in user to /signedin?requestId=device_... automatically called completeDeviceAuthorization() on page render without displaying a consent prompt or verifying that the browser had entered the user_code. Version 4.19.5 moves approval to an explicit server action on /device/consent bound by a short-lived deviceCodeCheck cookie.

Separately, in Keycloak (org.keycloak:keycloak-services < 26.6.4 and org.keycloak:keycloak-policy-enforcer < 26.0.10, CVE-2026-9800 / GHSA-f5p5-6xmx-p252), Policy Enforcer bypassed all role, scope, and UMA permission checks whenever the incoming request URI contained the configured access-denied-path string as a path segment or query parameter, allowing any authenticated user to reach protected endpoints.

Detection and remediation

# 1. Check Kubernetes clusters for vulnerable cert-manager and aws-privateca-issuer versions and direct Challenges
kubectl get deployment -n cert-manager -o wide 2>/dev/null || true
kubectl get challenges.acme.cert-manager.io -A -o json 2>/dev/null | \
  jq -r '.items[] | select((.metadata.ownerReferences // []) | length == 0) | "\(.metadata.namespace)/\(.metadata.name) -> issuer=\(.spec.issuerRef.kind)/\(.spec.issuerRef.name)"'

# 2. Audit CertificateRequests where issuerRef.kind is missing or does not match AWSPCAIssuer / AWSPCAClusterIssuer
kubectl get certificaterequests.cert-manager.io -A -o json 2>/dev/null | \
  jq -r '.items[] | select(.spec.issuerRef.group == "awspca.cert-manager.io" and (.spec.issuerRef.kind != "AWSPCAIssuer" and .spec.issuerRef.kind != "AWSPCAClusterIssuer")) | "\(.metadata.namespace)/\(.metadata.name): kind=\(.spec.issuerRef.kind)"'

# 3. Check Go and Maven lockfiles for kubeflow/pipelines, zitadel, and keycloak
rg -n 'cert-manager|aws-privateca-issuer|kubeflow/pipelines|zitadel|keycloak-(services|policy-enforcer)' \
  go.mod pom.xml build.gradle* Chart.yaml values.yaml 2>/dev/null
  1. Upgrade cert-manager to >= 1.20.3 or >= 1.19.6 and audit any existing custom Role or ClusterRole manifests to ensure tenant service accounts do not hold create permissions on challenges.acme.cert-manager.io or orders.acme.cert-manager.io. If any ownerless Challenge resource was created in your cluster, rotate the ClusterIssuer DNS01 provider credentials immediately.
  2. Upgrade aws-privateca-issuer to >= 1.10.1 (or the EKS add-on to v1.10.1-eksbuild.1), and update every Certificate, CertificateRequest, and Ingress annotation to specify issuerRef.kind: AWSPCAIssuer or AWSPCAClusterIssuer explicitly.
  3. Upgrade Kubeflow Pipelines to >= 2.18.0 so volume artifact reads are confined to the volume root, ReadRunLogV1 enforces readLog RBAC and pod pipeline/runid labels, and archive uploads enforce ArchiveTraversalBudget.
  4. Upgrade ZITADEL to >= 4.19.5 and set a dedicated 32+ character ZITADEL_SESSION_COOKIE_SECRET (openssl rand -base64 32) on the Login V2 deployment.
  5. Upgrade Keycloak (org.keycloak:keycloak-services to >= 26.6.4 and org.keycloak:keycloak-policy-enforcer to >= 26.0.10).

Timeline

  • 2026-10-13: aws-privateca-issuer releases v1.10.1 (9ae225b695).
  • 2026-10-15: ZITADEL commits fixes for CVE-2026-119127 (6493aa908c), CVE-2026-119128 (e32ba7aa69), and CVE-2026-119129 (a618740b57) in v4.19.5.
  • 2026-10-28 to 2026-10-29: cert-manager releases v1.19.6 and v1.20.3 (6bda47297c, b37dbf01ec), Kubeflow Pipelines releases 2.18.0 (4d9bc5ab12, be4723e337, 1121d9a081, ba9ae72cc8), and NVD, AWS (2026-156-AWS), and the GitHub Advisory Database publish all ten advisories.

From research to remediation

Check whether this pattern exists in your codebase

Turn this research into a remediation workflow. Use AI-native static analysis to find similar application vulnerabilities and generate review-ready fixes.

References