Skip to content

Auto-PR Workflow Security Model

This document describes the security model for the auto-pr GitHub Actions workflows. It addresses CWE-829 (Improper Control of a Resource Through its Lifetime) and related supply-chain concerns.

When a workflow runs on a push to an ai/** branch, the pushed code may be from any collaborator or fork. An attacker could:

  • Push malicious code that runs during the workflow (e.g. modified package.json scripts, build scripts)
  • Poison artifacts that a privileged job later consumes
  • Exfiltrate secrets if untrusted code runs with access to them

The goal is to never execute untrusted code in a privileged context (secrets, pull-requests: write).

The auto-pr flow is split into two reusable workflows:

WorkflowCheckoutPermissionsSecrets
generate (auto-pr-generate-reusable.yml)Branch (github.ref_name)contents: read, models: readGH_TOKEN from caller (secrets.GH_TOKEN or github.token) for GitHub Models
create (auto-pr-create-reusable.yml)Default branch onlycontents: read, pull-requests: writeAPP_ID, APP_PRIVATE_KEY

The entry workflow (auto-pr.yml) must also include models: read in its top-level permissions when it calls the generate reusable workflow. Nested jobs cannot request broader GITHUB_TOKEN permissions than the caller grants (reusable workflows and permissions).

  • Checkout: The pushed branch — untrusted, but acceptable because the workflow has no privileged permissions.
  • Runs: auto-pr-generate-content (AI), artifact preparation.
  • Output: Artifact pr-content (title, body, branch, default_branch).
  • Risk: Limited. It cannot write to the repo. The job receives a token for GitHub Models as passed from the caller (repo GH_TOKEN secret or default github.token), not the App install secrets (APP_ID / APP_PRIVATE_KEY).

Create (Privileged, Trusted Checkout Only)

Section titled “Create (Privileged, Trusted Checkout Only)”
  • Checkout: github.event.repository.default_branch — trusted.
  • Input: Artifact from generate job.
  • Runs: GitHub App token generation, gh pr create or gh pr edit.
  • Risk: Mitigated. No untrusted code is checked out or executed. Artifact content is treated as data, not code.

The create workflow downloads the artifact produced by generate. Artifacts from unprivileged jobs are considered untrusted data:

  • Extraction: Artifact is downloaded to ${{ runner.temp }}/pr-artifact (not workspace) to avoid overwriting trusted files.
  • Usage: Artifact files (title.txt, body.md, branch.txt, default_branch.txt) are read as data and passed to gh. No scripts from the artifact are executed.
  • Validation: The create-or-update-pr CLI validates inputs before calling gh.

CodeQL flags “Checkout of untrusted code in trusted context” (CWE-829) when a workflow checks out potentially attacker-controlled refs while having privileged permissions. Our two-phase design satisfies the security intent:

  • Generate: untrusted checkout, unprivileged context
  • Create: trusted checkout only, privileged context

CodeQL does not fully model cross-workflow permission separation, so it may report false positives on reusable workflows. We exclude the untrusted-checkout queries via .github/codeql/codeql-config.yml; the security model above is preserved.