Guía9 min

pull_request_target: no lo uses como CI de forks

Resumen

pull_request_target corre en el contexto del repo base: secrets y GITHUB_TOKEN con write. Un agente que hace checkout del PR y pnpm test ahí filtra el secret. Para tests usa pull_request. Distinct de OIDC y de permissions. Docs GitHub events that trigger workflows.

GitHub
CI de fork en pull_request, no en pull_request_target con secrets

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.

on: pull_request en un fork no ve secrets del repo. on: pull_request_target sí: corre como si el workflow fuera del base. El token puede escribir. Por eso un agente que copia pull_request_target “para que el CI de forks pase” abre un agujero.

No sustituye permissions. OIDC es otro eje (cloud keys). El curso instalar un agente no cubre este evento.

Receta

CI de código:

on:
  pull_request:

Labeler / comment en el PR sin ejecutar el código del fork:

on:
  pull_request_target:
permissions:
  pull-requests: write
  contents: read

Si hace falta el diff, usa actions/checkout del base (ref: github.event.pull_request.base.sha). Nunca ref: github.event.pull_request.head.sha + pnpm test en el mismo job que tiene secrets.

Checkout del head + secrets = leak

Qué no hacer

  • Copiar un workflow de internet con pull_request_target y npm install del PR.
  • persist-credentials: true en ese checkout.
  • pull_request_target + workflow_run encadenado sin revisar qué código corre.

GitHub documenta el evento en “Events that trigger workflows”. El default de GITHUB_TOKEN en pull_request_target no es el de un PR de fork.

Receta AGENTS.md

Never use pull_request_target for running untrusted PR code.
CI tests: on: pull_request.
If labeling: checkout base SHA only; contents: read; no install from the fork.

Evento correcto vs el que da secrets

FAQ

¿Forks internos? Sigue siendo código no revisado. Mismo default.

¿Approve workflows? En forks, GitHub pide aprobación de first-time contributors. No lo eludas con _target.

¿script injection? Un run: echo ${{ github.event.pull_request.title }} también es un vector. Usa env.

Verificado 2026-09-03 contra GitHub Docs events that trigger workflows (pull_request vs pull_request_target).