GitHub Actions recibió un lockfile el 14 de octubre. Bloquea el código que revisaste. No lo revisa.

El miércoles 14 de octubre, GitHub puso en vista previa pública los lockfiles de dependencias de workflows para GitHub Actions, en los planes Enterprise Cloud (con o sin residencia de datos), Team y Free. Un archivo en .github/workflows/actions.lock, generado por una extensión de la CLI de GitHub llamada gh actions-lock, registra el commit exacto detrás de cada action que usa un workflow, incluidas las actions que esas actions llaman, y los workflows reutilizables de los que depende. Una vez incorporado un workflow, GitHub Actions ejecuta los commits registrados, aunque se mueva una etiqueta o una rama. Una política complementaria, Require lockfile, permite a los administradores de empresa, organización y repositorio hacerla obligatoria.
El anuncio es corto. Los docs, el README de la extensión y la discusión de diseño que la precedió no lo son, y contienen las partes que deciden si esto te protege o solo añade un archivo a tu repositorio.
Soy CTO de una LegalTech construida sobre Claude, y publico aplicaciones iOS y un juego de estrategia como desarrollador independiente. Productos distintos, la misma pregunta: un job de CI que guarda secretos ejecuta cada paso de terceros justo al lado de ellos. Así que lo leí todo.
Por qué una etiqueta es el punto débil
Cuando un workflow dice uses: some-org/some-action@v3, Actions resuelve v3 al commit al que apunta la etiqueta cuando arranca el job. Las etiquetas se pueden mover. Todo el ataque está ahí.
En marzo de 2025, unos atacantes "modificaron retroactivamente varias etiquetas de versión" de tj-actions/changed-files para que apuntaran a un commit malicioso, según su entrada en la GitHub Advisory Database, que sitúa la exposición el 14 y 15 de marzo y cifra el impacto en más de 23.000 repositorios. La carga leía los secretos de la memoria del runner y los imprimía en los logs de build.
El 19 de marzo de 2026 volvió a pasar. La cronología de Aqua Security dice que un atacante hizo force-push de 76 de las 77 etiquetas de versión de aquasecurity/trivy-action hacia commits maliciosos (los primeros recuentos externos, de Socket y Snyk, hablaban de 75 de 76). Los pipelines siguieron funcionando, escribe Aqua, "sin ningún indicio de que el código subyacente había cambiado".
Una semana después, el 26 de marzo, GitHub publicó su hoja de ruta de seguridad 2026 para Actions. Citaba tj-actions/changed-files, Nx y trivy-action, y fijaba un objetivo de tres a seis meses para una vista previa pública del bloqueo de dependencias. Llegó seis meses y 18 días después.
Qué registra el archivo
Los docs describen dos secciones. workflows lista las dependencias de cada workflow incorporado. dependencies lista, para cada una, el ref que escribiste (una etiqueta o rama), el commit al que se resolvió, y los owner_id y repo_id numéricos del repositorio de origen.
Tres detalles importan más que el propio anclaje.
El commit bloqueado debe existir en una rama del repositorio de origen. El README dice que es "para dificultar los ataques de tipo commit impostor". La discusión de diseño de GitHub lo planteó en mayo: un simple anclaje por SHA en un archivo de workflow no garantiza que el commit viva en el repositorio nombrado y no en un fork controlado por un atacante.
La identidad del repositorio se comprueba al arrancar el job. Según el README, el runner confirma que el repositorio no fue renombrado ni transferido, que el commit anclado sigue existiendo, y que una etiqueta de versión completa como v4.2.1 sigue apuntando a él. Una comprobación fallida bloquea la ejecución.
Y las composite actions ya no esconden sus propias líneas uses:, porque las dependencias transitivas también se anclan.
Para los repositorios que adoptan un lockfile, GitHub dice ahora que anclar por SHA dentro de los archivos de workflow "ya no es necesario".
El diseño que salió no es el que GitHub propuso primero. La hoja de ruta de marzo describía una sección dependencies: dentro del YAML del workflow, resuelta con la CLI de GitHub, y la discusión de mayo nombraba el comando que la escribiría, gh actions pin. Lo que salió es un archivo separado por repositorio, mantenido por una extensión. Creo que es la mejor elección: un solo archivo que comparar, una sola ruta que proteger.
Lo que el anuncio no cuenta
La extensión edita más que el lockfile. Reescribe las referencias a la versión concreta que resolvió, así que @v3 puede pasar a @v3.1.0, y convierte las actions del mismo repositorio en ./… a una sintaxis nueva $/… que siempre se resuelve al commit en ejecución. Revisa el diff completo, no solo el archivo nuevo.
Si tu organización restringe qué actions pueden ejecutarse, comprueba la lista de permitidas antes de hacer commit. Tras la incorporación, la lista se compara con los SHA de commit bloqueados, y las entradas ancladas a una etiqueta, como actions/checkout@v6, "ya no coinciden". Los docs dicen que uses un comodín o el SHA completo.
Los workflows reutilizables son una frontera. Tu lockfile ancla el workflow reutilizable que llamas, pero los docs dicen que sus propias dependencias las cubre el lockfile del repositorio donde está definido, y recomiendan incorporar primero los repositorios de workflows compartidos. Lo leo así: un workflow compartido de otro repositorio solo está bloqueado en la medida en que lo está ese repositorio.
Dependabot mantiene sincronizados los workflows incorporados, regenerando la entrada del lockfile en la misma pull request que la subida de versión. No incorporará un workflow por ti. "Solo avisa de que se requiere la incorporación".
La política Require lockfile se puede probar en modo Evaluate, pero los docs dicen que ese modo solo existe en GitHub Enterprise. En Free o Team, la política no tiene dry run.
Y es una vista previa. El README califica la extensión de pre-1.0 y avisa de que el formato del lockfile, las opciones de los comandos y el comportamiento "pueden cambiar sin previo aviso entre versiones". GitHub Enterprise Server no está soportado. El 19 de octubre, las páginas prácticas seguían listando solo GitHub Enterprise Cloud bajo "Who can use this feature?", mientras que el changelog listaba Team y Free en una nota del editor, fechada el 14 de octubre, que "actualizó qué planes tienen acceso".
El límite que GitHub escribe por sí mismo
"El bloqueo no determina si la dependencia en sí es segura, así que revisa las dependencias antes de bloquearlas." Esa frase está en el anuncio, y es la más importante. Si generas un lockfile mientras una etiqueta está envenenada, has anclado el malware, y cada ejecución posterior lo ejecutará fielmente.
Lo que cambia el lockfile es el momento en que te enteras. Las ramas y las versiones parciales como v3 o main se dan por buenas desde el lockfile y no se vuelven a resolver en una ejecución normal. Si una etiqueta upstream apunta ahora a otro sitio, la extensión se detiene con un error y decides tú. gh actions-lock --relock acepta un movimiento legítimo. Si el commit que bloqueaste ya no es alcanzable en absoluto, "por ejemplo porque el repositorio upstream hizo force-push o lo borró", incluso --relock da error, y necesitas --accept-moved. Esa es la opción que nunca dejaría que un script pasara por su cuenta.
La comprobación del commit impostor ya se ha puesto a prueba en público. El 15 de octubre, François Proulx, de Boost Security, informó en el seguimiento de incidencias de la extensión de que una entrada de lockfile editada a mano, asociada a un SHA completo que solo existía en un fork de actions/checkout, pasó gh actions-lock --verify y se ejecutó con el nombre del repositorio upstream en un repositorio con Require lockfile activo. Una ejecución nueva de gh actions-lock rechazaba el mismo commit. El 16 de octubre, un mantenedor respondió que el defecto del backend estaba corregido, y añadió: "Volveré a la brecha en la CLI la semana que viene". El 19 de octubre, la incidencia seguía abierta. El informe señala que el ataque exige que un colaborador haga cambios visibles tanto en el workflow como en el lockfile.
La guía de aplicación lo dice sin rodeos: "Un lockfile solo es un control de seguridad si alguien lee el diff". También sugiere una skill de Copilot que regenera el lockfile cada vez que el agente edita un workflow, y la llama "una comodidad más que un control". Yo orquesto mi trabajo con Claude Code, y la misma lógica vale para cualquier agente de código: una instrucción mantiene el archivo al día, no lo revisa.
Qué haría primero
- Activa Dependabot para GitHub Actions antes de crear el lockfile, como recomiendan los docs.
- Lista cada línea
uses:, comprueba que cada una apunta a una versión soportada y reciente, y mira el historial reciente de etiquetas de cada action de terceros que vas a bloquear. - Instala la extensión con
gh extension install github/gh-actions-locke incorpora un workflow pasándole su ruta. Empezaría por el que guarda los secretos de despliegue o de firma. - Revisa el diff completo y la lista de permitidas, y haz commit.
- Añade un job que ejecute
gh actions-lock --verifyen las pull requests y hazlo una comprobación obligatoria. Detecta un lockfile desfasado; el informe del 15 de octubre muestra que no sustituye leer una entrada editada a mano. En local,gh actions-lock --verify-local --no-fixfunciona sin conexión en un hook de pre-commit, pero solo comprueba que cada referencia tiene una entrada, no que las entradas sean de fiar. - Pon
.github/workflows/actions.locken CODEOWNERS y exige la aprobación de un code owner. - Activa Require lockfile solo cuando cada workflow objetivo esté incorporado y haya algo que lo mantenga así. Sabe lo que te compra: en otra incidencia, un mantenedor explicó el 15 de octubre por qué un lockfile roto no detiene las ejecuciones (fallar en modo cerrado afectaría a workflows que nunca se incorporaron) y dijo que la política Require lockfile "es lo que te da el comportamiento fail closed".
Encaja en una dirección que GitHub ya había tomado: el 10 de septiembre hizo cache-mode generalmente disponible en todos los planes, un ajuste de mínimo privilegio para la caché de Actions. Anclar lo que se ejecuta y limitar lo que puede tocar son las dos mitades del mismo trabajo.
Una etiqueta es una promesa hecha por la cuenta de otra persona. Un lockfile la convierte en un commit que elegiste tú. Elegir bien sigue siendo cosa tuya.
Fuentes
- GitHub Changelog, "GitHub Actions workflow lockfiles in public preview" (14 de octubre de 2026)
- GitHub Docs, "Workflow dependency lockfiles" (consultado el 19 de octubre de 2026)
- GitHub Docs, "Locking action dependencies in a repository's workflows" (consultado el 19 de octubre de 2026)
- GitHub Docs, "Enforcing lockfiles for action dependencies" (consultado el 19 de octubre de 2026)
- GitHub, "gh-actions-lock" (README) (consultado el 19 de octubre de 2026)
- gh-actions-lock, incidencia n.º 174, "Full-SHA lock entries can accept a fork-only commit under the upstream action name" (abierta el 15 de octubre de 2026, respuesta de un mantenedor el 16 de octubre, consultada el 19 de octubre de 2026)
- gh-actions-lock, incidencia n.º 125, "A broken action.lock file causes it to be ignored" (respuesta de un mantenedor el 15 de octubre de 2026)
- The GitHub Blog, "What's coming to our GitHub Actions 2026 security roadmap" (26 de marzo de 2026)
- GitHub Community, "Help Shape Workflow Dependency Locking" (1 de mayo de 2026)
- GitHub Advisory Database, "tj-actions changed-files through 45.0.7 allows remote attackers to discover secrets by reading actions logs" (consultado el 19 de octubre de 2026)
- Aqua Security, "Update: Ongoing Investigation and Continued Remediation" (relato del incidente de Trivy) (publicado el 22 de marzo de 2026, actualizado el 1 de abril de 2026)
- Snyk, "Trivy GitHub Actions Supply Chain Compromise" (20 de marzo de 2026)
- GitHub Changelog, "Control GitHub Actions cache access with cache-mode" (10 de septiembre de 2026)
