Skip to content

Esta herramienta no está afiliada a GitHub, Inc. ni a Microsoft Corporation, ni cuenta con su respaldo o patrocinio. GitHub y GitHub Actions son marcas comerciales de GitHub, Inc. Los demás nombres son marcas comerciales de sus respectivos propietarios.

¿Protección de ramas desactivada? Audita los rulesets

Investiga la manipulación de la protección de ramas y rulesets de GitHub: protected_branch.destroy, cambios de ruleset, overrides, entornos y lo que entró.

Publicado el 6 min de lectura

En resumen. La protección de ramas y los rulesets son lo que impide que una sola credencial robada reescriba main. Los atacantes los eliminan (protected_branch.destroy, repository_ruleset.destroy), los debilitan (protected_branch.update_*, repository_ruleset.update) o los eluden (protected_branch.policy_override). Hacen lo mismo con los entornos de despliegue (environment.remove_protection_rule). El registro de auditoría te dice quién cambió qué regla y cuándo. El historial de Git y los eventos Git te dicen qué entró mientras estaba desactivada. Restaura la regla y revisa después cada push, force-push y despliegue de esa ventana.

La revisión de código, las comprobaciones de estado obligatorias y los commits firmados son controles de la cadena de suministro. Solo funcionan mientras se aplican. Un atacante con permisos de administración o con el token de un propietario puede desactivarlos durante los minutos que necesite. Algunos los vuelven a activar después para ocultar el hueco. El registro de auditoría conserva los dos eventos.

Qué se puede manipular

ControlEliminado / borradoDebilitadoEludido
Protección de ramas clásicaprotected_branch.destroyprotected_branch.update_* (número de revisiones, comprobaciones de estado, force-pushes, borrados, aplicación a administradores…)protected_branch.policy_override
Rulesets de repositoriorepository_ruleset.destroyrepository_ruleset.updatebypass actors configurados en el ruleset
Entornos de despliegueenvironment.deleteenvironment.remove_protection_rule, environment.update_protection_rule—

La documentación de GitHub sobre ramas protegidas y rulesets describe cada ajuste. La entrada del glosario sobre rulesets de repositorio explica cómo se combinan los rulesets con la protección clásica.

Cómo lo señala el analizador

ReglaAccionesGravedad
branch-protection-removedprotected_branch.destroy, repository_ruleset.destroyalta
branch-protection-overrideprotected_branch.policy_overridemedia
environment-protection-removedenvironment.remove_protection_rule, environment.deletealta

Los hallazgos se agrupan por repositorio. Las acciones de debilitamiento (protected_branch.update_*, repository_ruleset.update) no son reglas, porque forman parte de la administración normal de un repositorio. Aparecen en la cronología porque allí se conservan todas las acciones protected_branch. y repository_ruleset.. Cuando salte un hallazgo, abre la cronología de ese repositorio y lee las actualizaciones que lo rodean.

Cómo leer una eliminación

Un evento protected_branch.destroy incluye el repositorio, el patrón de rama (name) y los ajustes que tenía la regla en ese momento, como required_approving_review_count y admin_enforced. Eso te dice qué se perdió. Después, responde a cuatro preguntas:

  1. ¿Quién y con qué? Actor, IP, user agent y hashed_token. Una sesión de navegador desde la oficina del propietario no es lo mismo que curl/8.5.0 con un token desde un VPS.
  2. ¿Se restauró, y quién lo hizo? Un protected_branch.create para la misma rama horas después, hecho por otro actor, suele significar que alguien se dio cuenta. Que el mismo actor la vuelva a crear minutos después apunta a un intento de ocultación.
  3. ¿Qué se subió entretanto? Filtra los eventos Git por git.push en ese repositorio dentro de la ventana y compáralos con el historial de commits de la rama. Los eventos Git excluyen los pushes hechos desde la interfaz web o la API, así que revisa también la vista de actividad del repositorio.
  4. ¿Se desplegó algo? Las ejecuciones de workflows en la rama por defecto durante la ventana (workflows.created_workflow_run con head_branch: main) pueden haber puesto el cambio en producción.

Los overrides son otra cosa

protected_branch.policy_override significa que un administrador del repositorio hizo push o merge mientras la regla seguía activa, usando su privilegio para saltársela. A menudo es legítimo: hotfixes o responsables de release con una excepción documentada. Por eso tiene gravedad media. Se vuelve interesante cuando la cuenta de administrador también tiene hallazgos de token o de ubicación, o cuando los overrides se concentran en rutas sensibles como .github/workflows/.

Entornos: los secretos detrás de la barrera

Las reglas de protección de entornos (revisores obligatorios, temporizadores, políticas de ramas de despliegue) suelen ser lo único que separa un workflow en una rama cualquiera de las credenciales cloud de producción guardadas como secretos de entorno. Eliminar una regla, o borrar el entorno y volver a crearlo, deja esos secretos al alcance de cualquier ejecución de workflow que haga referencia al entorno. Tras un hallazgo environment-protection-removed, lista las ejecuciones que usaron ese entorno durante la ventana y considera expuestos sus secretos. El artículo sobre secretos de Actions explica cómo acotarlo.

Force-pushes y reescrituras del historial

Las reglas suelen bloquear los force-pushes. Con la protección desactivada, un atacante puede reescribir el historial para introducir un commit malicioso o para borrar el rastro de uno. El registro de auditoría no guarda el contenido de los commits, pero todavía puedes trabajar con:

  • Los eventos git.push (si tienes los eventos Git) para la cronología y la credencial utilizada.
  • protected_branch.update_allow_force_pushes_enforcement_level, si el atacante solo relajó ese ajuste.
  • La vista de actividad del repositorio y tus mirrors o cachés de CI. Puede que aún conserven los commits anteriores a la reescritura.

Medir el hueco a mano

Si quieres contrastar la lectura del analizador, o solo tienes la exportación en bruto, la consulta es corta. Extrae todos los eventos de protección y de rulesets del repositorio, en orden cronológico, con el actor y la IP:

jq -r '.[] | select(.repo=="ORG/REPO")
  | select(.action|test("^(protected_branch|repository_ruleset|environment)\\."))
  | [(.["@timestamp"]/1000|todate), .action, .actor, (.actor_ip // "-"), (.name // "-")]
  | @tsv' audit-log.json | sort

Lee la salida por parejas. Cada destroy o update que debilita una regla debería ir seguido de un create o update que la restaura. El tiempo entre ambos es tu ventana de exposición. Anótala en UTC, porque todo lo demás del acotamiento (pushes, ejecuciones de workflows, despliegues) se filtra por esa ventana. Si no hay una restauración correspondiente, la ventana sigue abierta. Corrígelo antes de continuar con la investigación. Comprueba también si el debilitamiento y la restauración salieron de la misma cuenta. Cuando una persona desactiva la protección y la vuelve a activar alrededor de un único push, tienes que hablar con esa persona, sea cual sea el motivo al final.

Lista de remediación

  • Vuelve a crear la protección de ramas y los rulesets a partir de una definición fiable (mantén los rulesets como código, o expórtalos).
  • Restaura las reglas de protección de los entornos y rota los secretos del entorno.
  • Revisa cada commit, merge, force-push y despliegue hecho durante el hueco, y revierte o vuelve a desplegar desde un commit de confianza.
  • Elimina los bypass actors inesperados de los rulesets y los administradores de repositorio inesperados.
  • Para los controles más importantes, prefiere los rulesets de organización. Se gestionan a nivel de organización, no los administradores de cada repositorio.

Relacionado

Artículos relacionados

Indicios de toma de control de una organización de GitHub en el audit log: nuevos propietarios, 2FA desactivado, SSO SAML modificado, lista de IP y streaming.
Qué hacer si tu organización de GitHub está comprometida: conserva el registro de auditoría, contén tokens y workflows, acota con eventos Git y salta al cloud.
Lo que no guarda el registro de auditoría de GitHub: retención de 180 y 7 días, límites de plan, IP ocultas, sin contenido de archivos ni lecturas de secretos.

Esta herramienta no está afiliada a GitHub, Inc. ni a Microsoft Corporation, ni cuenta con su respaldo o patrocinio. GitHub y GitHub Actions son marcas comerciales de GitHub, Inc. Los demás nombres son marcas comerciales de sus respectivos propietarios.