Guía9 min

GITHUB_TOKEN en Actions: permissions mínimas, no un PAT de admin

Resumen

Cada job de GitHub Actions recibe GITHUB_TOKEN. El bloque permissions recorta contents, pull-requests, id-token. Un agente que escribe workflows con contents: write por default abre la puerta a un PR que pushea a main. Least privilege. Docs automatic token authentication.

GitHub
Un workflow con permissions contents read, sin PAT de admin

Qué resuelve

Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.

Un workflow nuevo con permissions: contents: write “porque checkout” es el default perezoso. actions/checkout funciona con read. Write hace que un job comprometido (script de un PR fork, o un action de terceros) pueda commitear con el token del repo.

GITHUB_TOKEN lo inyecta Actions. Caduca al terminar el job. Un PAT de admin en secrets no caduca y salta branch protection si el dueño es admin. No lo uses para CI de tests. Ver secretos.

El curso instalar un agente no cubre YAML de Actions. gh pr es el delivery; el workflow no mergea.

El bloque mínimo

permissions:
  contents: read

A nivel workflow o job. Si el job comenta en el PR:

permissions:
  contents: read
  pull-requests: write

OIDC a la nube: id-token: write sin contents write. Deploy: el job de deploy, no el de lint.

packages: read si tiras de ghcr. actions: read raro. security-events: write solo code scanning.

permissions read en el workflow

Qué no hace el agente

  • permissions: write-all
  • PAT GH_TOKEN con scope repo para un pnpm test
  • persist-credentials: true en checkout de un workflow que luego corre código de PR (el default de checkout persiste el token en .git; en forks hay que pensarlo)
  • pull_request_target + checkout del PR + token write (clásico de inyección)

Forks: GITHUB_TOKEN de pull_request no tiene write a secrets del repo. No “arregles” con pull_request_target para tener secrets.

Receta AGENTS.md

New workflows: permissions: contents: read unless a job proves it needs more.
Never add a PAT for CI that GITHUB_TOKEN covers.
Never write-all.
Do not add pull_request_target without a security review.

Job de test vs job de deploy

FAQ

¿Checkout necesita write? No para clonar. Write si el job pushea tags/commits (release). Ese job está aislado.

¿Default del org es read? Muchas orgs ya pusieron default read. El YAML explícito gana y se lee en el PR.

¿Matrix? permissions del job aplican a cada shard.

¿Reusable workflows? El caller y el callee tienen permissions distintas; no asumas write heredado.

Si un action de marketplace pide contents: write para “comentar un PR”, es el olor equivocado: eso es pull-requests: write. Pide el mínimo o no lo uses. Un agent que copia un workflow de un gist con write-all no “ahorra tiempo”: copia un agujero.

Verificado 2026-09-03 contra GitHub Docs — Automatic token authentication / assigning permissions to jobs.