CVE-2026-93991 Overview
CVE-2026-93991 is an authorization bypass vulnerability in Argo Workflows versions 4.1.0 through 4.1.3. The flaw resides in the ListArchivedWorkflows API endpoint, which fails to apply cluster-scoped access review when the metadata.namespace field selector uses the NotEquals operator. An attacker holding namespace-scoped list permissions can supply a negated namespace selector to enumerate archived workflows across every other namespace in the cluster. The exposed data includes workflow spec arguments, parameter values, and annotations, which frequently contain sensitive configuration or secrets references. The issue is tracked as [CWE-639] Authorization Bypass Through User-Controlled Key.
Critical Impact
A user restricted to a single namespace can bypass Kubernetes-style tenant isolation and read archived workflow metadata from all other namespaces in the Argo Workflows deployment.
Affected Products
- Argo Workflows 4.1.0
- Argo Workflows 4.1.1 through 4.1.2
- Argo Workflows 4.1.3
Discovery Timeline
- 2026-09-19 - CVE-2026-93991 published to the National Vulnerability Database
- 2026-09-22 - Last updated in NVD database
- Patch release - Fix shipped in Argo Workflows v4.1.4
Technical Details for CVE-2026-93991
Vulnerability Analysis
Argo Workflows exposes an archived workflow list API through server/workflowarchive/archived_workflow_server.go. The handler calls auth.CanI("list", "workflows", options.Namespace, "") to determine whether the caller is permitted to list workflows in the requested namespace. The check treats the Namespace field as the authoritative scope for the request. However, the same request may include a NamespaceFilter operator that changes the semantics of the query. When the operator is set to NotEquals, the resulting SQL condition returns rows from every namespace except the one supplied. The authorization layer never accounts for this inversion, so a caller granted list workflows in namespace team-a receives archived workflow records belonging to team-b, team-c, and any other tenant sharing the archive database.
Root Cause
The root cause is a mismatch between the authorization scope and the effective query scope. The permission check uses the literal namespace string, while the archive query uses that string plus a variable comparison operator. A negated operator effectively converts a namespace-scoped request into a cluster-wide read without triggering a corresponding cluster-scoped CanI evaluation.
Attack Vector
Exploitation requires an authenticated user with list permission on workflows in at least one namespace. The attacker issues a ListArchivedWorkflows gRPC or REST request with a metadata.namespace field selector using the NotEquals operator against their own namespace. The server returns archived workflow entries from every other namespace, exposing spec.arguments, parameter values, and annotations.
// Patch from server/workflowarchive/archived_workflow_server.go
// verify if we have permission to list Workflows
- allowed, err := auth.CanI(ctx, "list", workflow.WorkflowPlural, options.Namespace, "")
+ // A negated namespace selector returns every other namespace, so it needs cluster-wide permission
+ targetNamespace := options.Namespace
+ if options.NamespaceFilter == "NotEquals" {
+ targetNamespace = ""
+ }
+ allowed, err := auth.CanI(ctx, "list", workflow.WorkflowPlural, targetNamespace, "")
if err != nil {
return nil, sutils.ToStatusError(err, codes.Internal)
}
if !allowed {
- return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("Permission denied, you are not allowed to list workflows in namespace \"%s\"...", options.Namespace, options.Namespace))
+ return nil, status.Error(codes.PermissionDenied, fmt.Sprintf("Permission denied, you are not allowed to list workflows in namespace \"%s\"...", targetNamespace, targetNamespace))
}
Source: GitHub commit a40972386. The patch rewrites targetNamespace to an empty string when NamespaceFilter equals NotEquals, forcing auth.CanI to evaluate cluster-scoped permission before returning results.
Detection Methods for CVE-2026-93991
Indicators of Compromise
- Argo Workflows server access logs containing ListArchivedWorkflows requests with a namespace field selector using the NotEquals operator.
- HTTP query strings on the archive endpoint that include listOptions.fieldSelector=metadata.namespace!= patterns from accounts not associated with cluster-admin roles.
- Unusually large archived workflow list responses returned to service accounts scoped to a single namespace.
Detection Strategies
- Parse Argo Workflows server logs for archive list calls where the requesting subject's bound namespace differs from the namespaces present in the returned records.
- Correlate Kubernetes RBAC bindings with archive API access to identify callers whose effective read scope exceeds their granted namespace scope.
- Alert on any use of the NotEquals namespace selector against /api/v1/archived-workflows by non-administrative identities.
Monitoring Recommendations
- Enable audit logging on the Argo Workflows server and forward the events to a central analytics platform for retention and query.
- Baseline normal archive query volume per service account, then alert on deviations that suggest enumeration.
- Review database-level access to the workflow archive table for read patterns that ignore tenant namespace boundaries.
How to Mitigate CVE-2026-93991
Immediate Actions Required
- Upgrade all Argo Workflows server instances running versions 4.1.0 through 4.1.3 to v4.1.4 or later.
- Rotate any secrets, tokens, or credentials that may have been referenced in archived workflow spec arguments, parameters, or annotations.
- Audit archive access logs for the disclosed period to identify tenants whose data may have been enumerated.
Patch Information
The vulnerability is fixed by commit a40972386c097ddf816d2e60e13f058bedca53d9 and shipped in Argo Workflows v4.1.4. The fix rewrites the target namespace to an empty string when a negated selector is used, ensuring auth.CanI evaluates cluster-scoped list permission before returning results. See the GHSA-q65w-j2vp-47c4 advisory and the VulnCheck advisory for additional context.
Workarounds
- Disable the archived workflows API in the Argo Workflows server configuration until the upgrade is applied.
- Restrict access to the Argo Workflows server behind an authenticating reverse proxy that strips or rejects fieldSelector parameters containing != operators on metadata.namespace.
- Remove sensitive values from workflow spec arguments and annotations, and reference them exclusively through Kubernetes Secrets mounted at runtime.
# Verify running Argo Workflows server version and upgrade
kubectl -n argo get deploy argo-server -o jsonpath='{.spec.template.spec.containers[0].image}'
# Upgrade to the patched release
kubectl -n argo set image deploy/argo-server \
argo-server=quay.io/argoproj/argocli:v4.1.4
# Optional: temporarily disable the archive API until patched
kubectl -n argo patch configmap workflow-controller-configmap \
--type merge -p '{"data":{"persistence":"archive: false"}}'
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.
