Skip to content

SYSTEM Cited by 1 source

GitHub Actions

GitHub Actions is GitHub's native CI/CD platform: workflow files in .github/workflows/*.yml declare jobs that run on GitHub-hosted or self-hosted runners, triggered by repo events (push, PR, issue, schedule, webhook). It is the dominant CI substrate for open-source projects hosted on GitHub.

Security model — the substrate under attack

Script injection

${{ github.event.* }} expressions are string-interpolated into shell scripts before the shell parses them. Attacker-controlled fields (PR title, branch name, issue title, issue body, PR body, commit message, and — as in the Datadog datadog-iac-scanner attack — filenames matched by git diff) can carry shell metacharacters that trigger command execution. concepts/github-actions-script-injection is the class; canonical mitigation is patterns/environment-variable-interpolation-for-bash: route untrusted data through an env: key and reference as "$TITLE" in the bash snippet. GitHub publishes secure-use guidance recommending this pattern explicitly.

Token permissions

Every job receives a GITHUB_TOKEN. Default permissions are org-configurable; narrowing to read-only by default and opting-in to pull-requests: write / contents: write per-workflow limits blast radius.

pull_request_target / workflow_run

Strictly avoided — they run on trusted contexts with access to secrets, which makes them prime targets for script-injection exploits.

OIDC identity federation

GitHub Actions can act as an OpenID Connect (OIDC) identity provider. Workflows can exchange a short-lived OIDC token for cloud-provider credentials (AWS STS, Azure, GCP, PyPI) at runtime, replacing long-lived secrets stored in the repo. Canonical pattern: patterns/short-lived-oidc-credentials-in-ci. GitHub-specific short-lived-credential projects built on this include octo-sts (Chainguard) and dd-octo-sts-action (Datadog's adaptation) for dynamic GitHub PAT replacement.

Organization-level rulesets

GitHub rulesets enforce protections at the org level: required PRs for default branches, restricted write access to tags, and prevention of GitHub Actions from creating or approving PRs. patterns/org-wide-github-rulesets is the hardening pattern.

Static analysis

zizmor is the canonical linter for workflow-security issues — run with zizmor --min-severity high across an org's workflows before shipping changes to tighten known high-risk patterns.

LLM-powered actions

A growing class of actions invoke LLMs on repo events — the most widely deployed is anthropics/claude-code-action (>10,000 public workflows as of 2026-03). These actions are susceptible to prompt injection from attacker-controlled PR/issue/commit text. Datadog's 2026-03-09 post catalogs five best practices: write untrusted data to a file, then instruct the LLM to read it, treat LLM output as untrusted, scope tools to specific files, use recent models (less prone to injection), and keep the LLM step out of secret-bearing contexts.

Scheduled workflows as a cron substrate

Beyond event-triggered CI, GitHub Actions schedule: triggers turn the platform into a free, observable cron scheduler — a common use case for repo automation, periodic audits, and cross-service sync bots.

The pattern that emerges when the scheduled work involves incremental processing of external state (e.g. upstream PRs) is patterns/stateful-github-actions-cron: GitHub Actions cron for compute, an external database for state, go-github or an equivalent API client for repo operations. Stateful beats stateless because it makes incremental-pull stopping criteria cheap and reconciliation a single SQL join rather than a full-history scrape.

Canonical instantiation: systems/vitess-cherry-pick-bot — runs hourly on GitHub Actions with state in a PlanetScale database, continuously mirrors OSS Vitess PRs into PlanetScale's private fork, opens draft PRs on conflict, handles label-triggered backports to release branches, and runs a second weekly workflow for reconciliation. Production track record ~1.5 years at time of the post. (Source: )

Operational constraints for this use case:

  • Scheduling is best-effort — cron jobs can be delayed under GitHub-wide load. If strict timing matters, self-host.
  • No overlap protection by default — use concurrency: to serialise.
  • API rate limits — use conditional requests / ETags to stay inside budgets.
  • Secrets surface — DB credentials and API tokens in secrets: should be scoped narrowly; avoid pull_request_target with attacker-influenced inputs.

Seen in

Seen in

  • PR-bot altitude. Coutermarsh (2024) describes a GitHub Actions bot that detects Rails migration files in PRs, creates a PlanetScale branch via the planetscale_rails gem, opens a deploy request against production, and posts the link back on the PR along with class-of-change deploy-order instructions. Canonical instance of patterns/pr-bot-auto-deploy-request — a pattern where CI substrate (GitHub Actions) + migration executor (planetscale_rails)
  • schema-change unit (deploy request) compose into an end-to-end workflow that keeps code-deploy and schema-deploy decoupled while co-locating review. Coutermarsh generalises: "a similar workflow can be achieved with other CI tools as well" — the pattern is substrate-independent (GitLab CI, Buildkite, CircleCI, Jenkins all work).
Last updated · 542 distilled / 1,571 read