Die 10 kritischsten Sicherheitsrisiken in CI/CD-Pipelines und wie man sie entschärft.
In den OWASP Top 10 CI/CD-Sicherheitsrisiken werden die wichtigsten Sicherheitsrisiken in Continuous Integration- und Continuous Delivery-Pipelines identifiziert. CI/CD-Pipelines sind hochwertige Ziele, da sie direkten Zugang zu Quellcode, Geheimnissen und Produktionsumgebungen haben. Dieser Leitfaden befasst sich mit Flusskontrolle, Identitätsmanagement, Angriffen auf Abhängigkeiten, Pipeline Poisoning und mehr.
Unzureichende Flusskontrollmechanismen ermöglichen es Angreifern, bösartigen Code durch CI/CD-Pipelines zu schleusen, ohne ihn ordnungsgemäß zu überprüfen oder zu genehmigen. Dazu gehören die Umgehung von Verzweigungsschutzregeln, das Fehlen erforderlicher Genehmigungen und die fehlende Durchsetzung der Frage, wer Bereitstellungen für die Produktion auslösen kann.
Ohne ordnungsgemäße Flusskontrolle kann ein einziges kompromittiertes Entwicklerkonto oder ein böswilliger Insider Code direkt in die Produktion einspeisen und dabei Codeprüfung, Sicherheitsscans und Genehmigungsprozesse umgehen. Dies kann zur Bereitstellung von Hintertüren, Code zur Datenexfiltration oder zerstörerischen Nutzdaten führen.
# No branch protection — anyone can push directly to main name: Deploy on: push: branches: [main] # Triggers on any push to main jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: | # Deploys immediately — no approval gate! kubectl apply -f deploy.yaml kubectl rollout status deployment/myapp
name: Deploy on: push: branches: [main] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm test deploy: needs: test runs-on: ubuntu-latest environment: production # Requires manual approval steps: - uses: actions/checkout@v4 - run: | kubectl apply -f deploy.yaml kubectl rollout status deployment/myapp
CI/CD-Systeme umfassen mehrere Identitäten: menschliche Benutzer, Dienstkonten, Bot-Tokens und Maschinenidentitäten. Unzureichendes IAM ermöglicht einen zu weitreichenden Zugriff auf Repositorys, Pipelines und Bereitstellungsziele. Gemeinsam genutzte Anmeldedaten, veraltete Konten und fehlende MFA erhöhen das Risiko.
Kompromittierte CI/CD-Identitäten mit übermäßigen Berechtigungen können Pipelines ändern, auf Geheimnisse zugreifen, Build-Artefakte verändern und in der Produktion einsetzen. Gemeinsame Dienstkonten machen es unmöglich zu überprüfen, wer eine Aktion durchgeführt hat.
# Over-permissive workflow with admin token name: CI on: push permissions: write-all # Full permissions to everything! jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: | # Using org-wide PAT with admin access curl -H "Authorization: token ${{ secrets.ADMIN_PAT }}" \ https://api.github.com/repos/org/other-repo/contents/
name: CI on: push permissions: contents: read # Minimum required permissions packages: write # Only what's needed jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: actions/create-github-app-token@v1 # Scoped app token id: app-token with: app-id: ${{ vars.APP_ID }} private-key: ${{ secrets.APP_PRIVATE_KEY }} repositories: other-repo # Scoped to specific repo
CI/CD-Pipelines ziehen Abhängigkeiten von externen Paketregistrierungen (npm, PyPI, Maven, Docker Hub). Angreifer nutzen dies durch Abhängigkeitsverwirrung, Typosquatting, kompromittierte Betreuer-Konten und bösartige Pakete aus. Eine einzige vergiftete Abhängigkeit kann während des Builds beliebigen Code ausführen.
Bösartige Abhängigkeiten führen während der Installation Code aus (Postinstall-Skripte, setup.py), stehlen Geheimnisse, injizieren Hintertüren in Build-Artefakte oder stellen Persistenz her. Angriffe auf die Lieferkette wie SolarWinds und Codecov zeigen die katastrophalen Auswirkungen.
pipeline { agent any stages { stage('Build') { steps { // No lockfile verification, no integrity checks sh 'npm install' // Fetches latest — could be compromised! sh 'pip install -r requirements.txt' // No hash verification } } } }
pipeline { agent any stages { stage('Build') { steps { // Use lockfile with integrity verification sh 'npm ci' // Uses package-lock.json sh 'npm audit --audit-level=high' // Python: verify hashes from lockfile sh 'pip install --require-hashes -r requirements.lock' } } stage('SCA Scan') { steps { // Software Composition Analysis sh 'trivy fs --scanners vuln,secret .' } } } }
Poisoned Pipeline Execution (PPE) tritt auf, wenn Angreifer CI/CD-Pipeline-Definitionen ändern oder bösartigen Code einschleusen können, der im Pipeline-Kontext ausgeführt wird. Dies kann durch die Manipulation von Pipeline-Konfigurationsdateien in Zweigen, Pull-Requests von Forks oder die Änderung gemeinsam genutzter Pipeline-Vorlagen geschehen.
Ein Angreifer, der die Konfiguration der Pipeline ändern kann, erhält Zugriff auf alle Geheimnisse, Anmeldedaten und Berechtigungen, die für die Pipeline verfügbar sind. Er kann Geheimnisse exfiltrieren, Build-Ausgaben manipulieren oder bösartigen Code bereitstellen - alles in einem vertrauenswürdigen Ausführungskontext.
# Runs pipeline from fork PRs with access to secrets name: CI on: pull_request_target: # Runs in base repo context with secrets! branches: [main] jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 with: ref: ${{ github.event.pull_request.head.sha }} # Checks out fork code! - run: make build # Fork's Makefile executes with secrets access env: DEPLOY_KEY: ${{ secrets.DEPLOY_KEY }}
# Separate workflows: untrusted build + trusted deploy name: CI on: pull_request: # No secret access for PR builds branches: [main] permissions: contents: read jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 # Checks out merge commit (safe) - run: npm ci && npm test # No secrets needed for build/test - uses: actions/upload-artifact@v4 with: name: build-output path: dist/
Pipeline-basierte Zugriffskontrollen (PBAC) regeln, auf welche Ressourcen eine Pipeline zugreifen kann: Cloud-Konten, Kubernetes-Cluster, Datenbanken und interne Dienste. Eine unzureichende PBAC bedeutet, dass Pipelines einen breiteren Zugriff als nötig haben, was gegen das Prinzip der geringsten Privilegien verstößt.
Überprivilegierte Pipelines können ausgenutzt werden, um auf Ressourcen zuzugreifen, die weit über den vorgesehenen Umfang hinausgehen. Eine kompromittierte Build-Pipeline für einen unbedeutenden Dienst könnte verwendet werden, um auf Produktionsdatenbanken zuzugreifen, die Infrastruktur zu ändern oder auf andere Umgebungen zu wechseln.
# Pipeline with admin-level cloud credentials deploy: stage: deploy script: - aws configure set aws_access_key_id $AWS_ACCESS_KEY - aws configure set aws_secret_access_key $AWS_SECRET_KEY # This key has AdministratorAccess policy! - aws s3 sync dist/ s3://my-bucket/ - aws ecs update-service --cluster prod --service myapp # Same credentials could access ANY AWS resource
name: Deploy on: push: branches: [main] permissions: id-token: write # For OIDC contents: read jobs: deploy: runs-on: ubuntu-latest steps: - uses: aws-actions/configure-aws-credentials@v4 with: role-to-assume: arn:aws:iam::123456:role/deploy-s3-only # Scoped role: only s3:PutObject on specific bucket aws-region: us-east-1 - run: aws s3 sync dist/ s3://my-bucket/
CI/CD-Pipelines verarbeiten zahlreiche Anmeldeinformationen: API-Schlüssel, Cloud-Tokens, Registrierungspasswörter, SSH-Schlüssel und Signierzertifikate. Zu einer schlechten Anmeldeinformationshygiene gehören das Festcodieren von Geheimnissen in Pipelinedateien, das Drucken von Geheimnissen in Protokollen, die Verwendung unverschlüsselter Geheimnisspeicher und das ständige Rotieren von Anmeldeinformationen.
Durchgesickerte CI/CD-Anmeldeinformationen sind einer der häufigsten Vektoren für den Erstzugriff. Geheimnisse, die in Build-Protokollen offengelegt, an Repositories übergeben oder unverschlüsselt gespeichert werden, ermöglichen Angreifern den direkten Zugriff auf Produktionssysteme, Cloud-Konten und Artefaktregistrierungen.
#!/bin/bash # Secrets hardcoded and leaked in logs export DOCKER_PASSWORD="MyS3cret!" # Hardcoded! echo "Logging in with $DOCKER_PASSWORD" # Printed to logs! docker login -u admin -p "$DOCKER_PASSWORD" registry.example.com docker push registry.example.com/myapp:latest # AWS credentials in environment — visible in process listing export AWS_SECRET_ACCESS_KEY="wJalrXUtnFEMI/K7MDENG/bPxRfiCY" aws s3 cp artifact.zip s3://releases/
name: Publish on: push: tags: ['v*'] jobs: publish: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - uses: docker/login-action@v3 # Handles credentials securely with: registry: registry.example.com username: ${{ secrets.DOCKER_USER }} # Masked in logs password: ${{ secrets.DOCKER_TOKEN }} # Short-lived token - run: | docker build -t registry.example.com/myapp:${{ github.ref_name }} . docker push registry.example.com/myapp:${{ github.ref_name }}
CI/CD-Systeme (Jenkins, GitLab, GitHub Actions runners) werden häufig mit unsicheren Standardkonfigurationen betrieben. Dazu gehören veraltete Softwareversionen, ungeschützte Verwaltungsschnittstellen, deaktivierte Sicherheitsfunktionen, ein zu freizügiger Netzwerkzugriff und selbst gehostete, projektübergreifende Runner.
Eine falsch konfigurierte CI/CD-Infrastruktur kann ausgenutzt werden, um unbefugten Zugriff auf Build-Umgebungen zu erhalten, Geheimnisse abzufangen oder auf interne Netzwerke zuzugreifen. Gemeinsam genutzte, selbst gehostete Läufer ermöglichen projektübergreifende Angriffe, bei denen ein kompromittierter Workflow andere beeinträchtigt.
// Jenkins with insecure configuration // - Script console enabled without auth // - Agent-to-controller access unrestricted // - Outdated plugins with known CVEs pipeline { agent any // Runs on any available agent — no isolation stages { stage('Build') { steps { // Running as root on shared agent sh 'whoami' // root sh 'docker build -t myapp .' } } } }
pipeline { agent { kubernetes { // Ephemeral, isolated pod per build yaml """ apiVersion: v1 kind: Pod spec: securityContext: runAsNonRoot: true runAsUser: 1000 containers: - name: builder image: builder:1.2.3 securityContext: allowPrivilegeEscalation: false readOnlyRootFilesystem: true """ } } stages { stage('Build') { steps { container('builder') { sh 'make build' } } } } }
CI/CD-Pipelines werden häufig mit Diensten von Drittanbietern integriert: Codequalitäts-Tools, Sicherheitsscanner, Benachrichtigungssysteme und Bereitstellungsplattformen. Für diese Integrationen werden Zugriffstoken und Berechtigungen vergeben, wodurch eine Vertrauenskette entsteht. Eine unkontrollierte Nutzung bedeutet, dass man nicht weiß, worauf Drittanbieterdienste zugreifen oder was sie tun können.
Ein kompromittierter Drittanbieterdienst (wie die Codecov-Panne) kann auf Quellcode, Geheimnisse und Build-Artefakte zugreifen. Ohne Governance können Teams unbekannten Diensten übermäßig viele Berechtigungen gewähren und so unsichtbare Angriffsvektoren in der Lieferkette schaffen.
name: CI on: push jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm test # Unknown third-party action with full repo access - uses: random-org/code-analysis@main # Unpinned, unvetted! with: token: ${{ secrets.GITHUB_TOKEN }} # Full token access! # Uploading coverage to external service with repo token - run: | bash <(curl -s https://example.com/uploader.sh) # Remote script!
name: CI on: push permissions: contents: read jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: npm test # Vetted action pinned to SHA - uses: github/codeql-action/analyze@8a470fddafa5cbc14 # Pinned SHA # Upload via official CLI tool, not remote scripts - uses: codecov/codecov-action@e28ff129e5465c2c0dcc6f003fc735cb6ae0c673 with: token: ${{ secrets.CODECOV_TOKEN }} # Scoped token fail_ci_if_error: true
Build-Artefakte (Container-Images, Binärdateien, Pakete) fließen durch CI/CD-Pipelines in die Produktion. Ohne Integritätsprüfung können Artefakte zu jedem Zeitpunkt manipuliert werden: während der Erstellung, während der Übertragung, in der Artefaktregistrierung oder zum Zeitpunkt der Bereitstellung. Dadurch wird die Vertrauenskette vom Code bis zur Produktion unterbrochen.
Manipulierte Artefakte können Backdoors, Malware oder modifizierte Logik enthalten. Ohne Signierung und Verifizierung gibt es keine Möglichkeit zu erkennen, ob ein Artefakt nach der Erstellung verändert wurde. Angreifer können legitime Images in Registern ersetzen oder Artefakte während der Übertragung abfangen.
#!/bin/bash # Build and deploy without any integrity checks docker build -t myregistry.com/app:latest . docker push myregistry.com/app:latest # On deployment side — no verification docker pull myregistry.com/app:latest # Could be tampered! docker run myregistry.com/app:latest # Tag is mutable!
name: Build and Sign on: push: tags: ['v*'] permissions: id-token: write packages: write jobs: build: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - run: | # Build with immutable tag (SHA) docker build -t myregistry.com/app:${{ github.sha }} . docker push myregistry.com/app:${{ github.sha }} - uses: sigstore/cosign-installer@v3 - run: | # Sign image with keyless signing (Sigstore) cosign sign myregistry.com/app:${{ github.sha }} # Generate and attach SBOM syft myregistry.com/app:${{ github.sha }} -o spdx-json > sbom.json cosign attest --predicate sbom.json myregistry.com/app:${{ github.sha }}
CI/CD-Umgebungen erzeugen kritische Sicherheitsereignisse: Pipeline-Ausführungen, Konfigurationsänderungen, geheime Zugriffe und Bereitstellungsaktivitäten. Ohne umfassende Protokollierung und Überwachung bleiben böswillige Aktivitäten in der Pipeline unentdeckt, und die Reaktion auf Vorfälle wird erheblich erschwert.
Ohne Einblick in die CI/CD-Aktivitäten können Angreifer Pipelines verändern, Geheimnisse exfiltrieren und Artefakte manipulieren, ohne dass dies zu Warnmeldungen führt. Das Fehlen von Prüfprotokollen macht es unmöglich, den Umfang und die Auswirkungen eines Verstoßes zu bestimmen.
#!/bin/bash # Pipeline with no logging or audit trail echo "Starting deployment..." kubectl apply -f deploy.yaml echo "Done." # No record of: who triggered this, what changed, # which image was deployed, what secrets were accessed # Build logs expire after 30 days with no archival
name: Audited Deploy on: push: branches: [main] jobs: deploy: runs-on: ubuntu-latest steps: - uses: actions/checkout@v4 - name: Log deployment metadata run: | echo "=== Deployment Audit Log ===" echo "Triggered by: ${{ github.actor }}" echo "Commit: ${{ github.sha }}" echo "Ref: ${{ github.ref }}" echo "Workflow: ${{ github.workflow }}" echo "Run ID: ${{ github.run_id }}" - name: Deploy with audit run: | kubectl apply -f deploy.yaml 2>&1 | tee deploy.log # Send audit event to SIEM curl -X POST "${{ secrets.SIEM_WEBHOOK }}" \ -d '{"event":"deploy","actor":"${{ github.actor }}","sha":"${{ github.sha }}"}'
| ID | Schwachstelle | Schweregrad | Schlüssel Abschwächung |
|---|---|---|---|
| CICD-SEC-1 | Unzureichende Mechanismen zur Flusskontrolle | Critical | Branchenschutz, erforderliche Zulassungen, Umwelttore |
| CICD-SEC-2 | Unzureichendes Identitäts- und Zugangsmanagement | Critical | Token mit geringsten Rechten, OIDC, MFA, Rotation von Anmeldedaten |
| CICD-SEC-3 | Missbrauch der Abhängigkeitskette | Critical | Sperrdateien, Hash-Verifizierung, private Registraturen, SCA |
| CICD-SEC-4 | Vergiftete Pipeline-Ausführung (PPE) | Critical | Getrennte Erstellung/Entwicklung, unveränderliche Pipeline-Definitionen, Fork-Kontrollen |
| CICD-SEC-5 | Unzureichende PBAC | High | OIDC-Verbund, skalierte IAM-Rollen, Umgebungstrennung |
| CICD-SEC-6 | Unzureichende Zeugnishygiene | Critical | Geheimnisverwaltung, Protokollmaskierung, Rotation, geheimes Scannen |
| CICD-SEC-7 | Unsichere Systemkonfiguration | High | Kurzlebige Läufer, Nicht-Root, Plugin-Updates, Netzwerkisolierung |
| CICD-SEC-8 | Unkontrollierte Nutzung von Drittanbieterdiensten | High | Dienstinventar, SHA-Pinning, keine entfernten Skripte |
| CICD-SEC-9 | Unsachgemäße Validierung der Artefaktintegrität | High | Mitsignieren, Zulassungskontrolle, SLSA-Provenienz |
| CICD-SEC-10 | Unzureichende Protokollierung und Sichtbarkeit | Medium | Audit-Protokollierung, SIEM-Integration, Alarmierung, Protokollspeicherung |