Skip to main content

What the check does

Flags any workflow whose on: block subscribes to repository_dispatch without declaring an explicit types: allowlist. The check passes when:
  • The workflow does not subscribe to repository_dispatch at all, or
  • The subscription declares a non-empty types: list.
It fires for the three syntactic shapes that all amount to “unfiltered”:

Why it matters

repository_dispatch is GitHub’s “external system kicks off a workflow” hook. The dispatcher only needs a token with repo scope (a PAT, a fine-grained token, or a GitHub App installation token). Without types:, any caller can trigger the workflow with any event_type and any client_payload. Common consequences:
  • A third-party service you onboarded for one purpose (say, “rebuild on Sentry release”) becomes a generic build-pipeline trigger.
  • A leaked token can be used to trigger the workflow as a covert channel — for example, to run expensive jobs, exfiltrate secrets via deliberately-failing steps, or quietly poison caches.
  • The workflow’s inputs (via ${{ github.event.client_payload.* }}) are attacker-controlled JSON, often passed unchecked into shell scripts.
Pinning types: doesn’t fix the input-trust problem, but it limits the trigger surface to event types you’ve actually planned for.

Vulnerable example

Safe alternative

Treat every value under github.event.client_payload.* as untrusted: assign it to an env var (Pipefort’s CICD-SEC-4 check enforces this for the well-known PR contexts) and validate it before use.