Three branch labels and one risky assumption
A museum website accepts pull requests with changes to caption files. A workflow is supposed to run a stricter accessibility check when the proposed change targets the protected publishing branch, while lighter checks can run for a staging target. If the workflow mistakes the contributor’s source branch for the target, the wrong check may run or be skipped. GitHub provides `GITHUB_BASE_REF` for the target branch of supported pull request events. It is useful context, but it is not itself an authorization decision. The scenario here is a workflow design example, not evidence from a real repository or security test.
Read the precise meaning of GITHUB_BASE_REF
GitHub’s variables reference defines `GITHUB_BASE_REF` as the base or target branch name in a pull request workflow, available for `pull_request` and `pull_request_target` events. For instance, the value may be `main`. By contrast, `GITHUB_HEAD_REF` names the source branch, while `GITHUB_REF` may identify a synthetic pull request merge ref for a normal unmerged pull request event. The distinctions are operational, not cosmetic. Use the documented context for the question you actually need to answer. A workflow triggered by push or manual dispatch should not expect this variable to be populated as if it were a pull request.
Choose the correct event and permissions boundary
Start with an unprivileged `pull_request` workflow for checks of untrusted contributions. Set the minimum `GITHUB_TOKEN` permissions needed for reading files and producing status, and avoid giving write access merely to label a report. GitHub’s `pull_request_target` event runs in the base branch context and has important security implications when code from a fork is involved. Do not check out and execute untrusted fork code with privileged credentials. Record the chosen event, token permissions, and approval rules before relying on the branch label. The fact that a PR targets `main` should trigger review requirements, not automatic publication rights.

Pass the branch as data, not shell source
When a script needs the base branch, pass `${{ github.base_ref }}` through a quoted environment value or read the runner-provided `GITHUB_BASE_REF`, then validate it as a branch name. Avoid embedding event-controlled values directly inside executable shell program text or `eval`. Branch names can contain punctuation that breaks fragile scripts or makes logs misleading. Treat all event metadata as untrusted input for command construction, even when a target branch normally comes from a controlled repository. Do not use a string comparison as proof that the runner checked out the intended code: examine the checkout configuration separately.
Keep head, base, and merge inputs straight
Caption QA may need to compare files changed by the PR against the actual target branch. The head branch points to proposed contributor work; the base branch is the intended destination; a merge ref may represent the tentative combined result. Deciding which to test depends on whether the check assesses incoming files in isolation, the merge result, or branch-policy compliance. A workflow that fetches only the head may miss base-dependent paths; a workflow that assumes `GITHUB_REF` is a target name can select the wrong files. Record commit SHAs and fetched refs for reproducibility rather than relying on branch names alone.
Create branch-sensitive tests without skipping core QA
If a caption PR targets the publishing branch, run the full accessibility and rights checks. If it targets a staging branch, the workflow may run extra preview tests, but critical caption safety checks should not disappear. Write explicit conditions for recognized target branches and a safe default for unknown targets. Do not let contributor-controlled text choose a privileged deployment job. A GitHub branch protection rule or required status check is a separate enforcement mechanism. A green job resulting from an `if` condition is not necessarily evidence that a skipped test executed. Make the report state which tests actually ran.

Compare the test report to the changed files
A reviewer should be able to see the target branch, actual changed caption files, check names, and any skipped or failed stages. Use synthetic sample captions when experimenting with workflow logic. Do not include unpublished visitor interviews or private transcript content in public artifacts. Preserve the PR and commit references, because a branch can move between the time a workflow starts and the time a human reviews it. If the target branch was retargeted, require an appropriate recheck against the new base. A workflow event is a snapshot, not a perpetual guarantee about the current pull request state.
Handle reruns and manual events separately
Rerunning a job does not necessarily recreate the original event payload or update the base reference to the newest branch state. Check what the workflow actually received and what commits it tested; do not infer the current target from a historical log alone. For manual workflows, define an explicitly reviewed input branch rather than pretending `GITHUB_BASE_REF` is always available. Keep a distinction between the triggering actor, the person requesting a rerun, and the person authorized to approve a release. Previous LabFin articles cover those other variables; the purpose here is the target branch and the resulting scope of a caption QA check.
Review the security boundary before deployment
Inspect every use of the base ref in workflow expressions, shell commands, artifact labels, and checkout parameters. Confirm that branch-controlled text never becomes executable code, that the workflow uses least-privileged credentials, and that untrusted PRs cannot gain secrets by choosing a familiar target name. If a test must access protected publishing resources, isolate that task from the untrusted PR environment and require normal approval. Consider tests with a branch that contains punctuation, a retargeted PR, and an unrelated push event. These are proposed validation cases, not tests performed by LabFin on a production repository.

Release gate for caption changes
Before allowing a caption edit to enter a publishing branch, verify the current target, reviewed commit, completed checks, and editorial approval separately. Save the check results and scope in a way that can be audited without publishing private transcript data. Treat `GITHUB_BASE_REF` as a useful label for which branch a PR proposes to change, not an indicator that the contributor has permission to merge. The diagrams in this guide are conceptual representations of head, base, and merge refs. GitHub Actions context behavior and event security guidance should be rechecked whenever a workflow changes its triggers or privileges.
How We Research
We consulted the official GitHub Actions variables reference and GitHub Actions contexts reference. We compared the documented request or environment fields with their response and authorization limits, then created a hypothetical museum workflow and original conceptual illustrations. We did not access a live organization, deploy a workflow, perform vendor-side tests, inspect real customer records, or measure performance or security outcomes. Features, availability, pricing, and required permissions can change; confirm the current vendor documentation and your own policies before implementing these steps.
Frequently Asked Questions
No. That is the head/source branch; GITHUB_BASE_REF names the pull request target.
GitHub documents it for pull_request and pull_request_target workflows, not generic push events.
No. A branch label is not authorization, and workflows must apply separate event and permissions controls.
Not interchangeably. On a normal unmerged pull_request event it may identify a merge ref, not the base branch name.
Treat it as data, use safe quoting and validation, and avoid turning workflow metadata into executable script text.
