Воспроизводит CVE-2026-42880 — критическую уязвимость ArgoCD, раскрывающую Kubernetes Secrets через ServerSideDiff. Включает автоматическую настройку лабораторной среды, скрипты запуска и шаблон обнаружения Nuclei для тестирования безопасности.
Лабораторная среда для воспроизведения и обнаружения CVE-2026-42880 — критической уязвимости в Argo CD, при которой gRPC-обработчик ServerSideDiff раскрывает данные секретов Kubernetes пользователям с доступом только на чтение.
| Поле | Детали |
|---|
| ID CVE | CVE-2026-42880 |
| GHSA | GHSA-3v3m-wc6v-x4x3 |
| CVSS | 9.6 (критическая) — AV:N/AC:L/PR:L/UI:N/S:C/C:H/I:H/A:N |
| Затронутые версии | ArgoCD 3.2.0–3.2.10, 3.3.0–3.3.8 |
| Исправленные версии | 3.2.11, 3.3.9+ |
| CWE | CWE-200, CWE-212 |
Функция serverSideDiff() в gRPC-обработчике ArgoCD вызывает Kubernetes SSA dry-run и возвращает predictedLive без вызова hideSecretData(), раскрывая значения секретов в base64 в ответе.
Уязвимый путь (v3.2.0):
argocd app diff --server-side-diff
→ gRPC-обработчик ServerSideDiff
→ Kubernetes SSA dry-run (объединяет ВСЕ field manager'ы)
← predictedLive возвращается (включая данные external-controller)
❌ hideSecretData() НЕ вызывается → реальные значения секретов раскрыты
Исправленный путь (v3.2.11):
...тот же SSA dry-run...
✅ HideSecretData() вызывается → значения заменены на ++++
Все три условия должны выполняться одновременно:
| # | Условие | Детали |
|---|---|---|
| 1 | Уязвимая версия ArgoCD | 3.2.0–3.2.10 или 3.3.0–3.3.8 |
| 2 | Аннотация приложения | argocd.argoproj.io/compare-options: ServerSideDiff=true,IncludeMutationWebhook=true |
| 3 | Внешний field manager на данных Secret | Поля data секрета принадлежат менеджеру, отличному от ArgoCD (например, External Secrets Operator, Helm, kubectl) |
Требуется только role:readonly — права на запись не нужны.
Host Machine
├── localhost:30080 ──→ Kind Cluster: cve-vuln (ArgoCD v3.2.0 ⚠ УЯЗВИМ)
│ └── ns: production
│ ├── Secret: db-credentials
│ │ metadata → argocd-controller (синхронизирован из Git)
│ │ data.* → external-controller ⚠ (внедрён отдельно)
│ └── Secret: api-credentials (та же настройка)
│
├── localhost:30081 ──→ Kind Cluster: cve-patched (ArgoCD v3.2.11 ✓ ИСПРАВЛЕН)
│ └── (идентичная конфигурация — отличается только версия ArgoCD)
│
└── localhost:3010 ──→ Docker Container: cve-lab-gitea
└── repo: gitadmin/manifests.git
└── secret.yaml (без поля data — предусловие CVE)
Secret db-credentials (namespace: production)
┌──────────────────────────────────────────────────────────────┐
│ metadata.* → argocd-controller (ArgoCD синхронизирует из Git) │
│ data.* → external-controller (внедрён setup-скриптом) │
└──────────────────────────────────────────────────────────────┘
SSA dry-run: Kubernetes объединяет поля обоих менеджеров в predictedLive
→ ArgoCD НЕ владеет data → data не маскируется ArgoCD
→ v3.2.0 возвращает predictedLive без hideSecretData() → РАСКРЫТО
| Инструмент | Установка |
|---|---|
| kind | brew install kind |
| kubectl | brew install kubectl |
| Docker Desktop | docker.com |
| argocd CLI | brew install argocd |
| nuclei | brew install nuclei |
| curl, jq, git | предустановлены на macOS или brew install jq |
Требования к ресурсам: 8GB+ свободной RAM, 15GB+ свободного места на диске, доступные порты 30080 / 30081 / 3010.
bash scripts/01-setup-vuln.sh
# или: make setup-vuln
Занимает ~10 минут. По завершении:
══════════════════════════════════════════════════════
Уязвимая лаборатория ArgoCD готова!
══════════════════════════════════════════════════════
ArgoCD UI : http://localhost:30080
Admin pass : <сгенерирован автоматически>
Viewer pass : viewerpass123
Token file : .vuln-viewer-token
══════════════════════════════════════════════════════
bash scripts/02-setup-patched.sh
# или: make setup-patched
bash scripts/03-trigger-cve.sh
# или: make trigger
Ожидаемый результат — уязвимая версия (v3.2.0):
===== /Secret production/db-credentials ======
< db_password: ++++++++ ← замаскированное живое состояние
---
> db_password: U3VwM3JTM2NyM3REQiFQYXNzIzIwMjY= ← РАСКРЫТЫЙ predictedLive!
[EXPOSED] расшифровано: Sup3rS3cr3tDB!Pass#2026
⚠ РЕЗУЛЬТАТ: ДАННЫЕ СЕКРЕТА РАСКРЫТЫ — УЯЗВИМОСТЬ ПОДТВЕРЖДЕНА
Ожидаемый результат — исправленная версия (v3.2.11):
> db_password: ++++++++ ← замаскировано
✓ РЕЗУЛЬТАТ: незамаскированных данных в predictedLive нет — ИСПРАВЛЕНО
# Уязвимый кластер → должно появиться [critical] срабатывание
nuclei -t nuclei/CVE-2026-42880.yaml \
-u http://localhost:30080 \
-var username=viewer \
-var password=viewerpass123
# Исправленный кластер → срабатываний быть не должно
nuclei -t nuclei/CVE-2026-42880.yaml \
-u http://localhost:30081 \
-var username=viewer \
-var password=viewerpass123
bash scripts/99-teardown.sh
# или: make teardown
argocd-cve-2026-42880-lab2/
├── README.md
├── LAB_SETUP_GUIDE.md # Руководство по настройке лаборатории + устранение неполадок (англ.)
├── VULNERABILITY_ANALYSIS.md # Анализ уязвимости на уровне кода (англ.)
├── Nuclei_Template_Report.md # Разработка шаблона Nuclei и результаты тестов (англ.)
├── Makefile
│
├── REPORT/ # Отчёты на корейском
│ ├── LAB_REPORT_KR.md
│ ├── Nuclei_Template_Report_KR.md
│ └── Vulnerability_Analysis_KR.md
│
├── kind/
│ ├── cluster-vuln.yaml # Kind-кластер: cve-vuln (порт 30080)
│ └── cluster-patched.yaml # Kind-кластер: cve-patched (порт 30081)
│
├── git-manifests/
│ └── secret.yaml # Secret без поля data (предусловие CVE)
│
├── manifests/
│ ├── application.yaml # ArgoCD Application с уязвимой аннотацией
│ ├── argocd-cm-patch.yaml # ConfigMap: отключён TLS, учётная запись viewer, ServerSideDiff
│ ├── argocd-rbac-patch.yaml # RBAC: viewer → role:readonly
│ ├── argocd-nodeport.yaml # NodePort 30080 (уязвимый кластер)
│ └── argocd-nodeport-patched.yaml# NodePort 30081 (исправленный кластер)
│
├── nuclei/
│ └── CVE-2026-42880.yaml # Шаблон обнаружения Nuclei
│
└── scripts/
├── 01-setup-vuln.sh # Полная автоматическая настройка: уязвимое окружение
├── 02-setup-patched.sh # Полная автоматическая настройка: исправленное окружение
├── 03-trigger-cve.sh # Эксплуатация CVE + сравнение обоих кластеров
└── 99-teardown.sh # Удаление всех ресурсов лаборатории
Шаблон использует цепочку из 4 HTTP-шагов для проверки всех предусловий CVE без фактического извлечения секретов:
Шаг 1 GET /api/version
→ извлекаем argocd_version (аутентификация не требуется)
Шаг 2 POST /api/v1/session
→ аутентификация как viewer (role:readonly), извлекаем token
Шаг 3 GET /api/v1/applications
→ находим приложение с ServerSideDiff=true,IncludeMutationWebhook=true
Шаг 4 GET /api/v1/applications/{app}/managed-resources
→ проверяем: версия в диапазоне + Secret присутствует + f:data принадлежит внешнему менеджеру
→ СРАБАТЫВАНИЕ фиксируется только при выполнении всех 5 матчеров (условие И)
Предупреждение: Все учётные данные в этой лаборатории — фиктивные тестовые данные, предназначенные исключительно для исследований в области безопасности. Никогда не используйте в production.