¿Qué son los 10 Principales Riesgos de Seguridad CI/CD?

El OWASP Top 10 de Riesgos de Seguridad CI/CD identifica los riesgos de seguridad más significativos en los pipelines de Integración Continua y Entrega Continua. Los pipelines CI/CD son objetivos de alto valor porque tienen acceso directo al código fuente, secretos y entornos de producción. Esta guía cubre el control de flujo, la gestión de identidad, los ataques a dependencias, el envenenamiento de pipelines y más.

1�E�⃣ CICD-SEC-1 - Mecanismos de Control de Flujo Insuficientes

Critical

Descripción General

Los mecanismos de control de flujo insuficientes permiten a los atacantes enviar código malicioso a través de los pipelines CI/CD sin revisión o puertas de aprobación adecuadas. Esto incluye eludir las reglas de protección de ramas, la falta de aprobaciones requeridas y la falta de control sobre quién puede activar despliegues a producción.

Riesgo

Sin un control de flujo adecuado, una sola cuenta de desarrollador comprometida o un insider malicioso puede enviar código directamente a producción, eludiendo la revisión de código, los escaneos de seguridad y los procesos de aprobación. Esto puede llevar al despliegue de puertas traseras, código de exfiltración de datos o cargas destructivas.

Ejemplo de Código Vulnerable

YAML (GitHub Actions) ❁EMalo
# 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

Ejemplo de Código Seguro

YAML (GitHub Actions) ✁EBueno
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

Lista de Verificación de Mitigación

2�E�⃣ CICD-SEC-2 - Gestión Inadecuada de Identidad y Acceso

Critical

Descripción General

Los sistemas CI/CD involucran múltiples identidades: usuarios humanos, cuentas de servicio, tokens de bots e identidades de máquinas. La gestión inadecuada de IAM permite acceso excesivamente permisivo a repositorios, pipelines y objetivos de despliegue. Las credenciales compartidas, las cuentas obsoletas y la falta de MFA agravan el riesgo.

Riesgo

Las identidades CI/CD comprometidas con permisos excesivos pueden modificar pipelines, acceder a secretos, alterar artefactos de construcción y desplegar en producción. Las cuentas de servicio compartidas hacen imposible auditar quién realizó una acción.

Ejemplo de Código Vulnerable

YAML (GitHub Actions) ❁EMalo
# 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/

Ejemplo de Código Seguro

YAML (GitHub Actions) ✁EBueno
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

Lista de Verificación de Mitigación

3�E�⃣ CICD-SEC-3 - Abuso de la Cadena de Dependencias

Critical

Descripción General

Los pipelines CI/CD obtienen dependencias de registros de paquetes externos (npm, PyPI, Maven, Docker Hub). Los atacantes explotan esto a través de confusión de dependencias, typosquatting, cuentas de mantenedores comprometidas y paquetes maliciosos. Una sola dependencia envenenada puede ejecutar código arbitrario durante la construcción.

Riesgo

Las dependencias maliciosas ejecutan código durante la instalación (scripts postinstall, setup.py), robando secretos, inyectando puertas traseras en artefactos de construcción o estableciendo persistencia. Los ataques a la cadena de suministro como SolarWinds y Codecov demuestran el impacto catastrófico.

Ejemplo de Código Vulnerable

Jenkinsfile ❁EMalo
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
      }
    }
  }
}

Ejemplo de Código Seguro

Jenkinsfile ✁EBueno
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 .'
      }
    }
  }
}

Lista de Verificación de Mitigación

4�E�⃣ CICD-SEC-4 - Ejecución Envenenada de Pipeline (PPE)

Critical

Descripción General

La Ejecución Envenenada de Pipeline (PPE) ocurre cuando los atacantes pueden modificar las definiciones del pipeline CI/CD o inyectar código malicioso que se ejecuta dentro del contexto del pipeline. Esto puede suceder mediante la manipulación de archivos de configuración del pipeline en ramas, pull requests de forks o la modificación de plantillas de pipeline compartidas.

Riesgo

Un atacante que puede modificar la configuración del pipeline obtiene acceso a todos los secretos, credenciales y permisos disponibles para el pipeline. Puede exfiltrar secretos, alterar las salidas de construcción o desplegar código malicioso, todo dentro de un contexto de ejecución confiable.

Ejemplo de Código Vulnerable

YAML (GitHub Actions) ❁EMalo
# 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 }}

Ejemplo de Código Seguro

YAML (GitHub Actions) ✁EBueno
# 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/

Lista de Verificación de Mitigación

5�E�⃣ CICD-SEC-5 - Controles de Acceso Basados en Pipeline (PBAC) Insuficientes

High

Descripción General

Los Controles de Acceso Basados en Pipeline (PBAC) gobiernan a qué recursos puede acceder un pipeline: cuentas de la nube, clústeres de Kubernetes, bases de datos y servicios internos. Un PBAC insuficiente significa que los pipelines tienen un acceso más amplio del necesario, violando el principio de mínimo privilegio.

Riesgo

Los pipelines con privilegios excesivos pueden ser explotados para acceder a recursos mucho más allá de su alcance previsto. Un pipeline de construcción comprometido de un servicio menor podría usarse para acceder a bases de datos de producción, modificar infraestructura o pivotar a otros entornos.

Ejemplo de Código Vulnerable

YAML (GitLab CI) ❁EMalo
# 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

Ejemplo de Código Seguro

YAML (GitHub Actions) ✁EBueno
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/

Lista de Verificación de Mitigación

6�E�⃣ CICD-SEC-6 - Higiene de Credenciales Insuficiente

Critical

Descripción General

Los pipelines CI/CD manejan numerosas credenciales: claves API, tokens de la nube, contraseñas de registros, claves SSH y certificados de firma. La mala higiene de credenciales incluye codificar secretos en archivos de pipeline, imprimir secretos en logs, usar almacenamiento de secretos sin cifrar y nunca rotar credenciales.

Riesgo

Las credenciales CI/CD filtradas son uno de los vectores de acceso inicial más comunes. Los secretos expuestos en logs de construcción, confirmados en repositorios o almacenados sin cifrado proporcionan a los atacantes acceso directo a sistemas de producción, cuentas de la nube y registros de artefactos.

Ejemplo de Código Vulnerable

Bash (CI Script) ❁EMalo
#!/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/

Ejemplo de Código Seguro

YAML (GitHub Actions) ✁EBueno
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 }}

Lista de Verificación de Mitigación

7�E�⃣ CICD-SEC-7 - Configuración Insegura del Sistema

High

Descripción General

Los sistemas CI/CD (Jenkins, GitLab, runners de GitHub Actions) a menudo se ejecutan con configuraciones predeterminadas inseguras. Esto incluye versiones de software desactualizadas, interfaces de gestión expuestas, funciones de seguridad deshabilitadas, acceso de red excesivamente permisivo y runners autoalojados compartidos entre proyectos.

Riesgo

La infraestructura CI/CD mal configurada puede ser explotada para obtener acceso no autorizado a entornos de construcción, interceptar secretos o pivotar a redes internas. Los runners autoalojados compartidos permiten ataques entre proyectos donde un workflow comprometido afecta a otros.

Ejemplo de Código Vulnerable

Groovy (Jenkins) ❁EMalo
// 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 .'
      }
    }
  }
}

Ejemplo de Código Seguro

Groovy (Jenkins) ✁EBueno
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'
        }
      }
    }
  }
}

Lista de Verificación de Mitigación

8�E�⃣ CICD-SEC-8 - Uso No Gobernado de Servicios de Terceros

High

Descripción General

Los pipelines CI/CD a menudo se integran con servicios de terceros: herramientas de calidad de código, escáneres de seguridad, sistemas de notificación y plataformas de despliegue. Estas integraciones reciben tokens de acceso y permisos, creando una cadena de confianza. El uso no gobernado significa que no hay visibilidad sobre a qué pueden acceder o hacer los servicios de terceros.

Riesgo

Un servicio de terceros comprometido (como la brecha de Codecov) puede acceder al código fuente, secretos y artefactos de construcción. Sin gobernanza, los equipos pueden otorgar permisos excesivos a servicios desconocidos, creando vectores de ataque invisibles en la cadena de suministro.

Ejemplo de Código Vulnerable

YAML (GitHub Actions) ❁EMalo
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!

Ejemplo de Código Seguro

YAML (GitHub Actions) ✁EBueno
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

Lista de Verificación de Mitigación

9�E�⃣ CICD-SEC-9 - Validación Inadecuada de Integridad de Artefactos

High

Descripción General

Los artefactos de construcción (imágenes de contenedores, binarios, paquetes) fluyen a través de los pipelines CI/CD hacia producción. Sin validación de integridad, los artefactos pueden ser alterados en cualquier punto: durante la construcción, en tránsito, en el registro de artefactos o en el momento del despliegue. Esto rompe la cadena de confianza del código a producción.

Riesgo

Los artefactos alterados pueden contener puertas traseras, malware o lógica modificada. Sin firma y verificación, no hay forma de detectar si un artefacto fue modificado después de la construcción. Los atacantes pueden reemplazar imágenes legítimas en registros o interceptar artefactos en tránsito.

Ejemplo de Código Vulnerable

Bash ❁EMalo
#!/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!

Ejemplo de Código Seguro

YAML (GitHub Actions) ✁EBueno
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 }}

Lista de Verificación de Mitigación

🔟 CICD-SEC-10 - Registro y Visibilidad Insuficientes

Medium

Descripción General

Los entornos CI/CD generan eventos de seguridad críticos: ejecuciones de pipelines, cambios de configuración, acceso a secretos y actividades de despliegue. Sin registro y monitoreo exhaustivos, las actividades maliciosas en el pipeline pasan desapercibidas y la respuesta a incidentes se ve gravemente obstaculizada.

Riesgo

Sin visibilidad de las actividades CI/CD, los atacantes pueden modificar pipelines, exfiltrar secretos y alterar artefactos sin activar ninguna alerta. La falta de registros de auditoría hace imposible determinar el alcance y el impacto de una brecha.

Ejemplo de Código Vulnerable

Bash ❁EMalo
#!/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

Ejemplo de Código Seguro

YAML (GitHub Actions) ✁EBueno
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 }}"}'

Lista de Verificación de Mitigación

📊 Tabla de Resumen

ID Vulnerabilidad Severidad Mitigación Clave
CICD-SEC-1Mecanismos de Control de Flujo InsuficientesCriticalProtección de ramas, aprobaciones requeridas, puertas de entorno
CICD-SEC-2Gestión Inadecuada de Identidad y AccesoCriticalTokens de mínimo privilegio, OIDC, MFA, rotación de credenciales
CICD-SEC-3Abuso de la Cadena de DependenciasCriticalLockfiles, verificación de hashes, registros privados, SCA
CICD-SEC-4Ejecución Envenenada de Pipeline (PPE)CriticalSeparar construcción/despliegue, definiciones de pipeline inmutables, controles de fork
CICD-SEC-5PBAC InsuficienteHighFederación OIDC, roles IAM limitados, separación de entornos
CICD-SEC-6Higiene de Credenciales InsuficienteCriticalGestión de secretos, enmascaramiento de logs, rotación, escaneo de secretos
CICD-SEC-7Configuración Insegura del SistemaHighRunners efímeros, no-root, actualización de plugins, aislamiento de red
CICD-SEC-8Uso No Gobernado de Servicios de TercerosHighInventario de servicios, fijación a SHA, sin scripts remotos
CICD-SEC-9Validación Inadecuada de Integridad de ArtefactosHighFirma con Cosign, control de admisión, procedencia SLSA
CICD-SEC-10Registro y Visibilidad InsuficientesMediumRegistro de auditoría, integración SIEM, alertas, retención de logs