CVEReports
CVEReports

Automated vulnerability intelligence platform. Comprehensive reports for high-severity CVEs generated by AI.

Product

  • Home
  • Sitemap
  • RSS Feed

Company

  • About
  • Contact
  • Privacy Policy
  • Terms of Service

© 2026 CVEReports. All rights reserved.

Made with love by Amit Schendel & Alon Barad



CVE-2026-118761

CVE-2026-118761: Pre-Authorization Decompression Bomb Denial of Service in Kubeflow Pipelines API Server

Amit Schendel
Amit Schendel
Senior Security Researcher

Oct 31, 2026·11 min read·4 visits

Executive Summary (TL;DR)

Kubeflow Pipelines prior to 2.18.0 fails to bound uncompressed output streams and TAR PAX metadata during pipeline archive uploads. Because multipart upload handlers process archives prior to authorization checks, remote callers can submit small compression bombs to trigger an Out-Of-Memory (OOM) crash in the API server.

A high-severity Denial of Service (DoS) vulnerability exists in Kubeflow Pipelines prior to version 2.18.0 due to improper handling of highly compressed archive files (CWE-409). The API server decompresses uploaded ZIP and gzip-compressed TAR archives directly into memory without bounding the expanded byte stream or archive traversal metadata. Because decompression occurs before namespace-level authorization in multipart upload handlers, an unauthenticated or unauthorized attacker with network access to the API server can exhaust container heap memory and trigger Out-Of-Memory (OOM) terminations.

Vulnerability Overview

Kubeflow Pipelines provides an orchestration platform for building and deploying portable machine learning workflows on Kubernetes. A core component of this architecture is the API server (ml-pipeline-apiserver), which exposes HTTP and gRPC endpoints for managing pipelines, pipeline versions, experiments, and runs. Users register workflows by uploading compiled pipeline definitions packaged as YAML files or compressed archives (.zip, .tar.gz, or .tgz).

In Kubeflow Pipelines versions prior to 2.18.0, the archive extraction routines within the API server and the artifact reader in the persistence agent are vulnerable to resource exhaustion via data amplification (CWE-409: Improper Handling of Highly Compressed Data and CWE-400: Uncontrolled Resource Consumption). When processing an uploaded pipeline archive, the API server validates the size of the incoming compressed payload against a configured limit (common.MaxFileLength, defaulting to 32 MB), but fails to restrict the size of the decompressed output stream in memory.

Compounding the severity of this flaw is an architectural ordering issue within the multipart HTTP upload handlers (/apis/v1beta1/pipelines/upload and /apis/v2beta1/pipelines/upload). While remote URL-import handlers verify caller authorization before fetching and decompressing external archives, the multipart upload handlers extract and read the uploaded archive prior to evaluating namespace-level role-based access control (RBAC) permissions. Consequently, any network-reachable caller can force the API server to allocate arbitrary amounts of heap memory without possessing valid pipeline creation privileges.

When a small archive containing highly repetitive compressed data is submitted to these endpoints, the Go runtime attempts to buffer the entire uncompressed stream in memory. This rapidly depletes available RAM, causing the Go runtime to panic or the Linux kernel cgroup Out-Of-Memory (OOM) killer to terminate the ml-pipeline-apiserver container, resulting in a complete denial of service for pipeline management operations.

Root Cause Analysis

The root cause of CVE-2026-118761 spans four distinct technical flaws across the archive parsing utilities and HTTP client handlers in the Kubeflow Pipelines backend. The primary failure occurs in backend/src/apiserver/server/util.go, where the functions loadFile, DecompressPipelineTarball, and DecompressPipelineZip read uncompressed data into memory buffers before validating their length.

In loadFile, the function initialized a bufio.Reader and executed an unbounded for loop reading chunks of bufio.MaxScanTokenSize (64 KB), appending each chunk to a growing pipelineFile byte slice until io.EOF was reached. Only after the entire stream was buffered in memory did the function check whether len(pipelineFile) > MaxFileLength. Similarly, both DecompressPipelineTarball and DecompressPipelineZip invoked io.ReadAll() directly on the underlying tar.Reader and zip.File readers without wrapping them in a bounded reader.

Beyond single-file extraction, a secondary vulnerability vector exists in the way Go's standard library archive/tar package handles TAR archive traversal and metadata. When iterating through entries in a tarball using tarReader.Next(), the parser automatically skips leftover file padding and decodes PAX extended headers (tar.TypeXHeader) into memory before returning the target file header. An attacker can construct a TAR archive containing numerous decoy entries or oversized PAX metadata records preceding the target pipeline.yaml file. Even if individual file reads are capped, unconstrained calls to tarReader.Next() allow an archive to exhaust memory or CPU during header traversal.

Furthermore, subtle edge cases existed around boundary checks during TAR traversal. If a bounded reader wrapped the underlying gzip.Reader with an exact byte budget equal to traversalBudget, and tarReader.Next() consumed the final byte of that budget while simultaneously hitting io.EOF, checking for io.EOF prior to checking budget exhaustion could cause the parser to misinterpret a truncated bomb as a clean end-of-archive. Finally, in backend/src/agent/persistence/client/artifactclient/client.go, the persistence agent's ReadArtifact method also called io.ReadAll(resp.Body) without enforcing response size limits, exposing the agent to memory exhaustion when reading artifacts from storage.

Code Analysis

The remediation was implemented across two pull requests: PR #14171 (commit 1121d9a081fdf9e2107c39abb2cd8947727c6953) and PR #14186 (commit ba9ae72cc860e3afbea232185e4132fc2896cac5). The patches replace unbounded reads with io.LimitReader, introduce a total archive traversal budget for tarballs, and implement saturating arithmetic helpers to prevent integer overflows when calculating sentinel limits.

In backend/src/apiserver/server/util.go, the vulnerable loadFile loop and io.ReadAll calls were replaced with io.LimitReader bounded to MaxFileLength + 1. Reading one byte past the maximum allowed length allows the application to detect oversized inputs deterministically without allocating memory beyond the limit:

// Patched loadFile in backend/src/apiserver/server/util.go
func loadFile(fileReader io.Reader, MaxFileLength int) ([]byte, error) {
	// Wrap reader with a +1 sentinel byte using saturating addition to prevent int64 overflow
	limitedReader := io.LimitReader(fileReader, util.SaturatingAdd(int64(MaxFileLength), 1))
	pipelineFile, err := io.ReadAll(limitedReader)
	if err != nil {
		return nil, util.NewInvalidInputErrorWithDetails(err, "Error read pipeline file")
	}
	if len(pipelineFile) > MaxFileLength {
		return nil, util.NewInvalidInputError(
			"File size too large. Maximum supported size: %v", MaxFileLength)
	}
	return pipelineFile, nil
}

To address TAR metadata and padding amplification during tarReader.Next() calls, PR #14186 introduced util.ArchiveTraversalBudget(int64(maxFileLength)), which caps total decompressed bytes processed across the entire gzip stream (file content plus TAR headers and PAX records). The gzipReader is wrapped in an io.LimitedReader initialized with N: traversalBudget + 1:

// Patched decompressPipelineTarball in backend/src/apiserver/server/util.go
func decompressPipelineTarball(compressedFile []byte, maxFileLength int) ([]byte, error) {
	gzipReader, err := gzip.NewReader(bytes.NewReader(compressedFile))
	if err != nil {
		return nil, util.NewInvalidInputErrorWithDetails(err, "Error extracting pipeline from the tarball file. Not a valid tarball file")
	}
 
	traversalBudget := util.ArchiveTraversalBudget(int64(maxFileLength))
	// +1 sentinel byte allows distinguishing exact-budget reads from budget exhaustion
	limitedGzipReader := &io.LimitedReader{R: gzipReader, N: traversalBudget + 1}
 
	tarReader := tar.NewReader(limitedGzipReader)
	for {
		header, err := tarReader.Next()
		// CRITICAL: Check budget exhaustion BEFORE checking io.EOF
		if limitedGzipReader.N <= 0 {
			return nil, util.NewInvalidInputError("Archive extraction exceeded traversal budget of %v bytes", traversalBudget)
		}
		if errors.Is(err, io.EOF) {
			tarReader = nil
			break
		}
		if err != nil {
			return nil, util.NewInvalidInputErrorWithDetails(err, "Error extracting pipeline from the tarball file. Not a valid tarball file")
		}
		if header.Typeflag == tar.TypeReg {
			break
		}
	}
	// ... [Fallback logic if no regular file found] ...
 
	// Bound the target file read to maxFileLength + 1
	limitedReader := io.LimitReader(tarReader, util.SaturatingAdd(int64(maxFileLength), 1))
	decompressedFile, err := io.ReadAll(limitedReader)
	if limitedGzipReader.N <= 0 {
		return nil, util.NewInvalidInputError("Archive extraction exceeded traversal budget of %v bytes", traversalBudget)
	}
	if err != nil {
		return nil, util.NewInvalidInputErrorWithDetails(err, "Error reading pipeline YAML from the tarball file")
	}
	if len(decompressedFile) > maxFileLength {
		return nil, util.NewInvalidInputError("Decompressed file size too large. Maximum supported size: %v bytes", maxFileLength)
	}
	return decompressedFile, err
}

The two-stage fix in PR #14171 and PR #14186 is comprehensive regarding memory bounding. By enforcing both per-file limits (maxFileLength + 1) and stream-wide decompression budgets (traversalBudget + 1), and checking limitedGzipReader.N <= 0 prior to evaluating io.EOF, the patch prevents both simple file amplification bombs and complex PAX header traversal bombs. However, note that multipart upload decompression still occurs prior to authorization; the fix mitigates the impact by bounding the maximum memory allocation per request rather than reordering the authentication/authorization middleware.

Exploitation

Exploiting CVE-2026-118761 requires network connectivity to the Kubeflow Pipelines API server HTTP interface (commonly exposed on port 8888 internally or routed via an ingress gateway at /pipeline or /apis). Because decompression happens before namespace authorization in the multipart upload handlers, an attacker does not need valid pipeline creation privileges in a target namespace.

An attacker can exploit the vulnerability using two distinct payload construction techniques demonstrated in the official regression test suite (backend/src/apiserver/server/util_test.go and backend/src/common/util/tgz_test.go). The first technique is a direct file amplification bomb, where a large buffer of null bytes or repeating characters (e.g., 2 GB to 10 GB) is compressed into a pipeline.yaml entry inside a .zip or .tar.gz archive. Due to DEFLATE/gzip compression ratios on uniform data, a 10 GB stream compresses down to approximately 10 MB, easily passing the 32 MB compressed upload limit.

The second technique targets the TAR parser's internal metadata handling by constructing a pre-target PAX metadata bomb. As shown in the regression test fixture below, an attacker can write multiple decoy files containing ~700 KB PAX comment records (staying just beneath Go archive/tar's 1 MiB per-header limit) prior to the actual pipeline.yaml entry:

func createPreTargetPaxBomb(targetName string, targetContent string, paxPayloadBytes int64) []byte {
    var buf bytes.Buffer
    tw := tar.NewWriter(&buf)
 
    const maxPaxPerDecoy = 700 * 1024 // Split across decoys under archive/tar 1 MiB limit
    numDecoys := int((paxPayloadBytes + maxPaxPerDecoy - 1) / maxPaxPerDecoy)
    remainingPayload := paxPayloadBytes
 
    for i := 0; i < numDecoys; i++ {
        payloadForThisDecoy := remainingPayload
        if payloadForThisDecoy > maxPaxPerDecoy {
            payloadForThisDecoy = maxPaxPerDecoy
        }
        remainingPayload -= payloadForThisDecoy
 
        paxValue := fmt.Sprintf("%d comment=%s\n", payloadForThisDecoy, bytes.Repeat([]byte("x"), int(payloadForThisDecoy)-20))
        tw.WriteHeader(&tar.Header{
            Typeflag:   tar.TypeReg,
            Name:       fmt.Sprintf("decoy-%d.txt", i),
            Mode:       0600,
            Size:       1,
            PAXRecords: map[string]string{"comment": paxValue},
        })
        tw.Write([]byte("x"))
    }
 
    tw.WriteHeader(&tar.Header{
        Typeflag: tar.TypeReg,
        Name:     targetName,
        Mode:     0600,
        Size:     int64(len(targetContent)),
    })
    tw.Write([]byte(targetContent))
    tw.Close()
 
    var gzBuf bytes.Buffer
    gw := gzip.NewWriter(&gzBuf)
    gw.Write(buf.Bytes())
    gw.Close()
    return gzBuf.Bytes()
}

Once generated, the attacker transmits the archive via a standard multipart form POST request to /apis/v1beta1/pipelines/upload or /apis/v2beta1/pipelines/upload (or the /apis/v2beta1/pipelines/upload_version endpoint). To amplify the impact or bypass per-stream limits in partially mitigated environments, an attacker can send multiple concurrent upload requests, rapidly exhausting the pod's memory allocation.

Impact Assessment

CVE-2026-118761 carries a CVSS v3.1 base score of 7.5 (High) with the vector CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H. The vulnerability exclusively impacts system availability (A:H), with no direct impact on confidentiality (C:N) or integrity (I:N). The Attack Complexity is Low (AC:L) and Privileges Required is None (PR:N) because multipart archive extraction executes before namespace authorization checks.

When exploited, the ml-pipeline-apiserver process consumes memory until it hits the Kubernetes pod memory limit (resources.limits.memory) or exhausts available node memory. The Linux kernel cgroup OOM killer then terminates the container with exit code 137 (OOMKilled). While the API server is down or caught in a CrashLoopBackOff state due to repeated requests, all Kubeflow Pipelines control-plane operations fail. Users cannot upload pipelines, trigger scheduled runs, query experiment metadata, or view pipeline statuses in the UI.

If the Kubernetes deployment manifest for ml-pipeline-apiserver lacks explicit memory resource limits, the memory exhaustion can spill over to the underlying Kubernetes worker node. This can cause node-level memory pressure, triggering eviction of co-located pods or destabilizing the kubelet.

According to FIRST.org Exploit Prediction Scoring System (EPSS) data, the vulnerability has an EPSS score of 0.00495 (0.50%), placing it in the 42.47th percentile. The vulnerability is not currently listed in the CISA Known Exploited Vulnerabilities (KEV) catalog. However, because functional reproduction code is publicly available in the project's unit tests, targeted exploitation against exposed Kubeflow instances is straightforward.

Remediation

The primary remediation is to upgrade Kubeflow Pipelines to version 2.18.0 or later, which incorporates commits 1121d9a081fdf9e2107c39abb2cd8947727c6953 and ba9ae72cc860e3afbea232185e4132fc2896cac5. In version 2.18.0, all archive extraction paths in the API server and artifact response readers in the persistence agent enforce strict upper bounds on uncompressed byte streams and TAR metadata traversal.

> [!NOTE] > Upgrading to 2.18.0 bounds the maximum decompressed size of a single archive to MaxFileLength (32 MB by default) plus a fixed traversal overhead. However, because multipart decompression still occurs before namespace authorization, operators should also implement network-level access controls to prevent unauthenticated callers from sending high volumes of concurrent upload requests.

For environments where an immediate upgrade to 2.18.0 is not feasible, security engineers should apply the following defense-in-depth mitigations:

  1. Enforce Gateway Authentication and Authorization: Configure the ingress controller or service mesh (such as Istio AuthorizationPolicy or oauth2-proxy) to require valid authentication tokens and verify route-level access before forwarding requests to /apis/v1beta1/pipelines/upload* and /apis/v2beta1/pipelines/upload*.
  2. Restrict Network Exposure: Use Kubernetes NetworkPolicy resources to restrict ingress traffic to the ml-pipeline / ml-pipeline-apiserver pod on port 8888, allowing connections only from trusted ingress proxies and internal Kubeflow components.
  3. Configure Ingress Body Size Limits: Lower the maximum allowed HTTP request body size at the reverse proxy or ingress layer (for example, setting nginx.ingress.kubernetes.io/proxy-body-size: "5m") for pipeline upload routes to limit the size of compressed archives that can reach the API server.
  4. Enforce Kubernetes Pod Memory Limits: Verify that the ml-pipeline-apiserver deployment specifies strict resources.limits.memory and resources.requests.memory values so that an OOM condition is contained to the pod and cannot starve the underlying Kubernetes node.

Official Patches

KubeflowOfficial GitHub Security Advisory (GHSA-8fmv-6rg5-5924)
KubeflowKubeflow Pipelines 2.18.0 Release Notes
KubeflowPatch Commit 1121d9a081fdf9e2107c39abb2cd8947727c6953 (PR #14171)
KubeflowPatch Commit ba9ae72cc860e3afbea232185e4132fc2896cac5 (PR #14186)

Fix Analysis (2)

Technical Appendix

CVSS Score
7.5/ 10
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
EPSS Probability
0.50%
Top 58% most exploited

Affected Systems

Kubeflow Pipelines API Server (ml-pipeline-apiserver)Kubeflow Pipelines Persistence Agent (ml-pipeline-persistenceagent)

Affected Versions Detail

Product
Affected Versions
Fixed Version
Kubeflow Pipelines
Kubeflow
< 2.18.02.18.0
AttributeDetail
CVE / Advisory IDCVE-2026-118761 / GHSA-8fmv-6rg5-5924
Weakness ClassCWE-409: Improper Handling of Highly Compressed Data (Data Amplification)
CVSS v3.1 Score7.5 High (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H)
Attack VectorNetwork (Pre-authorization multipart HTTP archive upload)
EPSS Score0.50% (42.47th Percentile)
Primary ImpactDenial of Service via Container Out-Of-Memory (OOM) Termination
Affected VersionsKubeflow Pipelines < 2.18.0
Patched VersionKubeflow Pipelines 2.18.0

MITRE ATT&CK Mapping

T1190Exploit Public-Facing Application
Initial Access
T1499Endpoint Denial of Service
Impact
T1499.003Service Exhaustion
Impact
T1499.004Application Exploitation
Impact
CWE-409
Improper Handling of Highly Compressed Data (Data Amplification)

The software does not handle or incorrectly handles compressed inputs with a very high compression ratio that produces a large output when decompressed, consuming excessive memory or CPU resources.

Known Exploits & Detection

GitHub Pull Request #14171 (Unit Test Fixtures)Official regression tests demonstrating oversized ZIP and TAR.GZ archive generation and memory limit verification.
GitHub Pull Request #14186 (PAX Header Bomb Fixtures)Official regression test suite including createPreTargetPaxBomb to reproduce TAR PAX extended header traversal exhaustion.

Vulnerability Timeline

Pull Request #14171 merged to enforce uncompressed file size limits via io.LimitReader.
2026-08-27
Pull Request #14186 merged to enforce TAR traversal budgets against PAX metadata bombs and prevent integer overflows.
2026-08-31
GitHub Security Advisory GHSA-8fmv-6rg5-5924 and CVE-2026-118761 officially published.
2026-10-29
Advisory metadata updated confirming fix availability in Kubeflow Pipelines 2.18.0.
2026-10-30

References & Sources

  • [1]GitHub Security Advisory GHSA-8fmv-6rg5-5924
  • [2]CVE-2026-118761 Record on CVE.org
  • [3]NVD Vulnerability Detail for CVE-2026-118761
  • [4]Fix Commit: Bounded Reads & File Limits (PR #14171)
  • [5]Fix Commit: Tar Traversal Budget & Overflow Protection (PR #14186)
  • [6]Kubeflow Pipelines Pull Request #14171
  • [7]Kubeflow Pipelines Pull Request #14186
  • [8]Kubeflow Pipelines Release 2.18.0

Attack Flow Diagram

Press enter or space to select a node. You can then use the arrow keys to move the node around. Press delete to remove it and escape to cancel.
Press enter or space to select an edge. You can then press delete to remove it or escape to cancel.

More Reports

•11 minutes ago•CVE-2026-119203
7.1

CVE-2026-119203: Infinite Loop in pypdf Standard Cross-Reference Table Parser

CVE-2026-119203 is a denial-of-service vulnerability affecting the pypdf library in versions prior to 6.21.4. The flaw occurs within the standard cross-reference (xref) table parsing routine when processing truncated or malformed PDF streams that terminate before a valid trailer dictionary is encountered. Because the parser attempts to rewind the stream pointer by a fixed offset whenever the trailer token is absent without verifying forward progress, hitting the end-of-file (EOF) or non-advancing tokens causes the parser to re-read the same byte offset indefinitely. An unauthenticated attacker can exploit this flaw by supplying a crafted PDF document to an application using pypdf, resulting in continuous CPU consumption and thread exhaustion.

Amit Schendel
Amit Schendel
1 views•9 min read
•about 1 hour ago•CVE-2026-118759
7.5

CVE-2026-118759: Cross-Tenant Pod Log Exposure via Authorization Bypass in Kubeflow Pipelines

Prior to version 2.18.0, the Kubeflow Pipelines API server contains a missing authorization and confused deputy vulnerability in its run log streaming endpoint. The HTTP handler for `GET /apis/v1alpha1/runs/{run_id}/nodes/{node_id}/log` fails to propagate incoming request headers to gRPC metadata and omits caller authorization checks against the requested run. Furthermore, the backend accepts the caller-supplied `node_id` parameter directly as a Kubernetes pod name without verifying that the pod belongs to the specified pipeline run. An attacker with network access to the API server who knows a valid run identifier can read live or archived execution logs from any pod containing a `main` container within the run's Kubernetes namespace.

Alon Barad
Alon Barad
4 views•10 min read
•about 3 hours ago•CVE-2026-118763
7.4

CVE-2026-118763: Cross-Origin Credential Exposure in @sigstore/oci

A credential exposure vulnerability exists in the @sigstore/oci library prior to version 0.7.2. The RegistryClient implementation stores sensitive authentication headers, including Bearer tokens, Basic authentication credentials, and custom Docker configuration headers, as client-wide defaults on its shared HTTP client instance. When uploading binary blobs via the OCI distribution specification, the client extracts the target upload URI from the server-supplied Location header and dispatches an independent HTTP PUT request. If a compromised or untrusted registry returns a cross-origin URI in the Location header, the client transmits the stored authentication credentials directly to the third-party host.

Alon Barad
Alon Barad
7 views•10 min read
•about 6 hours ago•CVE-2026-119282
7.3

CVE-2026-119282: OS Command Injection via Plugin Options in Nx (@nx/maven and @nx/gradle)

An OS command injection and argument injection vulnerability exists in the Nx build system and its official Maven (@nx/maven) and Gradle (@nx/gradle) plugins. When constructing the project dependency graph, the plugins invoke underlying Java build wrappers via subshells while interpolating unsanitized plugin options directly from nx.json into the command arguments. An attacker who supplies a crafted nx.json file via a repository or pull request can execute arbitrary shell commands with the privileges of the user or CI/CD runner invoking any Nx command that computes the project graph.

Amit Schendel
Amit Schendel
6 views•10 min read
•about 7 hours ago•CVE-2026-59978
7.5

CVE-2026-59978: Persistent Denial of Service via Array Injection in AdminNeo

AdminNeo versions 4.6.2 through 5.4.1 contain an improper input validation vulnerability (CWE-20) in the version verification endpoint (?script=version). An unauthenticated remote attacker can submit a crafted HTTP POST request containing an array parameter for 'version', which is serialized into a shared server-side temporary cache file without type checking or authentication. On subsequent requests, the application deserializes this cached array and passes it to cookie() and rawurlencode(), triggering an uncaught fatal TypeError in PHP 8.x environments and causing a persistent 24-hour Denial of Service (DoS) for all users.

Amit Schendel
Amit Schendel
6 views•8 min read
•about 8 hours ago•GHSA-FGXM-5HVV-X4VH
5.3

GHSA-fgxm-5hvv-x4vh: Private Repository Enumeration via Go Module Discovery and HTTP Response Discrepancies in Soft Serve

Charmbracelet Soft Serve versions 0.5.0 through 0.12.2 contain an authorization bypass and observable response discrepancy vulnerability in the HTTP Git server. Remote attackers can determine the existence, exact names, and clone URLs of private repositories by issuing crafted Go remote import path discovery requests (?go-get=1) or by observing differential HTTP status codes across Git Smart HTTP, Dumb HTTP, and Git LFS endpoints.

Alon Barad
Alon Barad
7 views•12 min read