CVE-2026-42294
Description
Argo Workflows is an open source container-native workflow engine for orchestrating parallel jobs on Kubernetes. Prior to versions 3.7.14 and 4.0.5, the Webhook Interceptor loads the entire request body into memory before authenticating the request or verifying its signature. This occurs on the /api/v1/events/ endpoint, which is publicly accessible (albeit intended for webhooks). An attacker can send a request with an extremely large body (e.g., multiple gigabytes), causing the Argo Server to allocate excessive memory, potentially leading to an Out-Of-Memory (OOM) crash and denial of service. This issue has been patched in versions 3.7.14 and 4.0.5.
Affected products
1- Range: >= 4.0.0, < 4.0.5
Patches
17abb4de6c359Merge commit from fork
3 files changed · +33 −2
docs/webhooks.md+2 −0 modified@@ -14,6 +14,8 @@ Additionally create: * A secret named `argo-workflows-webhook-clients` listing the service accounts: [example](https://raw.githubusercontent.com/argoproj/argo-workflows/main/manifests/quick-start/base/webhooks/argo-workflows-webhook-clients-secret.yaml) +Webhook request bodies are limited to a maximum size of 2MB. + The secret `argo-workflows-webhook-clients` tells Argo: * What type of webhook the account can be used for, e.g. `github`.
server/auth/webhook/interceptor.go+10 −2 modified@@ -75,8 +75,16 @@ func (i *WebhookInterceptor) addWebhookAuthorization(r *http.Request, kube kuber return fmt.Errorf("failed to get webhook clients: %w", err) } // we need to read the request body to check the signature, but we still need it for the GRPC request, - // so read it all now, and then reinstate when we are done - buf, _ := io.ReadAll(r.Body) + // so read it all now, and then reinstate when we are done. + // Limit to 2MB to prevent denial-of-service via oversized webhook payloads. + const maxWebhookSize = 2 * 1024 * 1024 // 2MB + buf, err2 := io.ReadAll(io.LimitReader(r.Body, maxWebhookSize+1)) + if err2 != nil { + return fmt.Errorf("failed to read webhook request body: %w", err2) + } + if len(buf) > maxWebhookSize { + return fmt.Errorf("webhook request body exceeds maximum size of 2MB") + } defer func() { r.Body = io.NopCloser(bytes.NewBuffer(buf)) }() serviceAccountInterface := kube.CoreV1().ServiceAccounts(namespace) for serviceAccountName, data := range webhookClients.Data {
server/auth/webhook/interceptor_test.go+21 −0 modified@@ -76,6 +76,27 @@ func TestInterceptor(t *testing.T) { }) } +func TestInterceptorOversizedBody(t *testing.T) { + ctx := logging.TestContext(t.Context()) + k := fake.NewSimpleClientset( + &corev1.Secret{ + ObjectMeta: metav1.ObjectMeta{Name: "argo-workflows-webhook-clients", Namespace: "my-ns"}, + Data: map[string][]byte{ + "github": []byte("type: github\nsecret: sh!"), + }, + }, + ) + i := NewWebhookInterceptor(logging.RequireLoggerFromContext(ctx)).Interceptor(k) + w := httptest.NewRecorder() + // Create a body that exceeds 2MB + body := bytes.NewReader(make([]byte, 2*1024*1024+1)) + r := httptest.NewRequest("POST", "/api/v1/events/my-ns/my-d", body) + h := &testHTTPHandler{} + i(w, r, h) + assert.Equal(t, 403, w.Code) + assert.JSONEq(t, `{"message": "failed to process webhook request"}`, w.Body.String()) +} + func intercept(ctx context.Context, method string, target string, headers map[string]string) (*http.Request, *httptest.ResponseRecorder) { // set-up k := fake.NewSimpleClientset(
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
6- github.com/argoproj/argo-workflows/commit/7abb4de6c3599e2d5d960ba4d5de4cf1df109965nvdPatch
- github.com/argoproj/argo-workflows/security/advisories/GHSA-jcc8-g2q4-9fxqnvdExploitVendor Advisory
- github.com/advisories/GHSA-jcc8-g2q4-9fxqghsaADVISORY
- github.com/argoproj/argo-workflows/releases/tag/v3.7.14nvdRelease Notes
- github.com/argoproj/argo-workflows/releases/tag/v4.0.5nvdRelease Notes
- nvd.nist.gov/vuln/detail/CVE-2026-42294ghsa
News mentions
0No linked articles in our index yet.