Os 10 riscos de segurança mais críticos em pipelines CI/CD e como mitigá-los.
O OWASP Top 10 Riscos de Segurança CI/CD identifica os riscos de segurança mais significativos em pipelines de Integração Contínua e Entrega Contínua. Pipelines CI/CD são alvos de alto valor porque têm acesso direto ao código-fonte, segredos e ambientes de produção. Este guia abrange controle de fluxo, gerenciamento de identidade, ataques de dependência, envenenamento de pipeline e muito mais.
Mecanismos insuficientes de controle de fluxo permitem que invasores enviem código malicioso através de pipelines CI/CD sem revisão ou portas de aprovação adequadas. Isso inclui contornar regras de proteção de branch, ausência de aprovações obrigatórias e falta de imposição sobre quem pode acionar implantações em produção.
Sem controle de fluxo adequado, uma única conta de desenvolvedor comprometida ou insider malicioso pode enviar código diretamente para produção, contornando revisão de código, verificações de segurança e processos de aprovação. Isso pode levar à implantação de backdoors, código de exfiltração de dados ou cargas destrutivas.
# No branch protection Eanyone 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 Eno 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
Sistemas CI/CD envolvem múltiplas identidades: usuários humanos, contas de serviço, tokens de bot e identidades de máquina. IAM inadequado permite acesso excessivamente permissivo a repositórios, pipelines e alvos de implantação. Credenciais compartilhadas, contas obsoletas e falta de MFA agravam o risco.
Identidades CI/CD comprometidas com permissões excessivas podem modificar pipelines, acessar segredos, alterar artefatos de build e implantar em produção. Contas de serviço compartilhadas tornam impossível auditar quem realizou uma ação.
# 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
Pipelines CI/CD obtêm dependências de registros de pacotes externos (npm, PyPI, Maven, Docker Hub). Invasores exploram isso através de confusão de dependências, typosquatting, contas de mantenedores comprometidas e pacotes maliciosos. Uma única dependência envenenada pode executar código arbitrário durante o build.
Dependências maliciosas executam código durante a instalação (scripts postinstall, setup.py), roubando segredos, injetando backdoors em artefatos de build ou estabelecendo persistência. Ataques de cadeia de suprimentos como SolarWinds e Codecov demonstram o impacto catastrófico.
pipeline { agent any stages { stage('Build') { steps { // No lockfile verification, no integrity checks sh 'npm install' // Fetches latest Ecould 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 .' } } } }
A Execução de Pipeline Envenenada (PPE) ocorre quando invasores podem modificar definições de pipelines CI/CD ou injetar código malicioso que é executado dentro do contexto do pipeline. Isso pode acontecer através da manipulação de arquivos de configuração de pipeline em branches, pull requests de forks ou modificação de templates de pipeline compartilhados.
Um invasor que pode modificar a configuração do pipeline ganha acesso a todos os segredos, credenciais e permissões disponíveis para o pipeline. Ele pode exfiltrar segredos, adulterar saídas de build ou implantar código malicioso Etudo dentro de um contexto de execução confiável.
# 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/
Controles de Acesso Baseados em Pipeline (PBAC) governam quais recursos um pipeline pode acessar: contas de nuvem, clusters Kubernetes, bancos de dados e serviços internos. PBAC insuficiente significa que pipelines têm acesso mais amplo do que o necessário, violando o princípio de privilégio mínimo.
Pipelines com privilégios excessivos podem ser explorados para acessar recursos muito além do escopo pretendido. Um pipeline de build comprometido para um serviço menor poderia ser usado para acessar bancos de dados de produção, modificar infraestrutura ou pivotar para outros ambientes.
# 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/
Pipelines CI/CD manipulam inúmeras credenciais: chaves de API, tokens de nuvem, senhas de registro, chaves SSH e certificados de assinatura. Higiene de credenciais deficiente inclui codificar segredos em arquivos de pipeline, imprimir segredos em logs, usar armazenamento de segredos não criptografado e nunca rotacionar credenciais.
Credenciais CI/CD vazadas são um dos vetores de acesso inicial mais comuns. Segredos expostos em logs de build, commitados em repositórios ou armazenados sem criptografia fornecem aos invasores acesso direto a sistemas de produção, contas de nuvem e registros de artefatos.
#!/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 Evisible 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 }}
Sistemas CI/CD (Jenkins, GitLab, runners do GitHub Actions) frequentemente operam com configurações padrão inseguras. Isso inclui versões de software desatualizadas, interfaces de gerenciamento expostas, recursos de segurança desabilitados, acesso de rede excessivamente permissivo e runners auto-hospedados compartilhados entre projetos.
Infraestrutura CI/CD mal configurada pode ser explorada para obter acesso não autorizado a ambientes de build, interceptar segredos ou pivotar para redes internas. Runners auto-hospedados compartilhados permitem ataques entre projetos onde um workflow comprometido afeta outros.
// 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 Eno 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' } } } } }
Pipelines CI/CD frequentemente integram-se com serviços de terceiros: ferramentas de qualidade de código, scanners de segurança, sistemas de notificação e plataformas de implantação. Essas integrações recebem tokens de acesso e permissões, criando uma cadeia de confiança. Uso não governado significa nenhuma visibilidade sobre o que serviços de terceiros podem acessar ou fazer.
Um serviço de terceiros comprometido (como a violação do Codecov) pode acessar código-fonte, segredos e artefatos de build. Sem governança, equipes podem conceder permissões excessivas a serviços desconhecidos, criando vetores de ataque invisíveis na cadeia de suprimentos.
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
Artefatos de build (imagens de contêiner, binários, pacotes) fluem através de pipelines CI/CD para produção. Sem validação de integridade, artefatos podem ser adulterados em qualquer ponto: durante o build, em trânsito, no registro de artefatos ou no momento da implantação. Isso quebra a cadeia de confiança do código à produção.
Artefatos adulterados podem conter backdoors, malware ou lógica modificada. Sem assinatura e verificação, não há como detectar se um artefato foi modificado após o build. Invasores podem substituir imagens legítimas em registros ou interceptar artefatos em trânsito.
#!/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 Eno 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 }}
Ambientes CI/CD geram eventos de segurança críticos: execuções de pipeline, alterações de configuração, acesso a segredos e atividades de implantação. Sem registro e monitoramento abrangentes, atividades maliciosas no pipeline passam despercebidas e a resposta a incidentes é severamente prejudicada.
Sem visibilidade nas atividades CI/CD, invasores podem modificar pipelines, exfiltrar segredos e adulterar artefatos sem acionar nenhum alerta. A falta de trilhas de auditoria torna impossível determinar o escopo e o impacto de uma violação.
#!/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 | Vulnerabilidade | Severidade | Mitigação Principal |
|---|---|---|---|
| CICD-SEC-1 | Mecanismos Insuficientes de Controle de Fluxo | Critical | Proteção de branch, aprovações obrigatórias, portas de ambiente |
| CICD-SEC-2 | Gerenciamento Inadequado de Identidade e Acesso | Critical | Tokens de privilégio mínimo, OIDC, MFA, rotação de credenciais |
| CICD-SEC-3 | Abuso de Cadeia de Dependências | Critical | Lockfiles, verificação de hash, registros privados, SCA |
| CICD-SEC-4 | Execução de Pipeline Envenenada (PPE) | Critical | Separar build/deploy, definições imutáveis de pipeline, controles de fork |
| CICD-SEC-5 | PBAC Insuficiente | High | Federação OIDC, funções IAM com escopo, separação de ambientes |
| CICD-SEC-6 | Higiene de Credenciais Insuficiente | Critical | Gerenciamento de segredos, mascaramento de logs, rotação, escaneamento de segredos |
| CICD-SEC-7 | Configuração Insegura do Sistema | High | Runners efêmeros, não-root, atualização de plugins, isolamento de rede |
| CICD-SEC-8 | Uso Não Governado de Serviços de Terceiros | High | Inventário de serviços, fixação SHA, sem scripts remotos |
| CICD-SEC-9 | Validação Inadequada de Integridade de Artefatos | High | Assinatura Cosign, controle de admissão, proveniência SLSA |
| CICD-SEC-10 | Registro e Visibilidade Insuficientes | Medium | Registro de auditoria, integração SIEM, alertas, retenção de logs |