[PR #8879] [MERGED] chore(ci): harden GitHub Actions workflow permissions #25174

Closed
opened 2026-04-15 22:45:03 -05:00 by GiteaMirror · 0 comments
Owner

📋 Pull Request Information

Original PR: https://github.com/better-auth/better-auth/pull/8879
Author: @gustavovalverde
Created: 4/1/2026
Status: Merged
Merged: 4/1/2026
Merged by: @gustavovalverde

Base: mainHead: chore/harden-workflow-permissions


📝 Commits (2)

  • 0cb92e3 chore(ci): harden GitHub Actions workflow permissions
  • ef57065 fix(ci): skip zizmor SARIF upload on fork PRs

📊 Changes

10 files changed (+94 additions, -10 deletions)

View changed files

📝 .github/workflows/ci.yml (+11 -0)
📝 .github/workflows/claude.yml (+3 -0)
📝 .github/workflows/demo.yml (+5 -0)
📝 .github/workflows/e2e.yml (+12 -1)
📝 .github/workflows/npm-dist-tag.yml (+5 -3)
📝 .github/workflows/preview.yml (+5 -0)
📝 .github/workflows/release.yml (+7 -4)
📝 .github/workflows/semantic-pull-request.yml (+3 -2)
.github/workflows/zizmor.yml (+31 -0)
.github/zizmor.yml (+12 -0)

📄 Description

Summary

Every workflow now follows a deny-all default: permissions: {} at the top level forces each job to declare only the permissions it actually needs. This eliminates the risk of compromised actions inheriting broad token access from repository defaults.

The changes fall into 3 categories: access control, supply chain hardening, and injection prevention.

Access control

  • permissions: {} on all 9 workflows (lock-threads already had it). Each job now declares its own minimal grant: contents: read for CI jobs, contents: write + id-token: write for the release job, pull-requests: write for the semantic PR validator.
  • persist-credentials: false on all actions/checkout steps (10 total). Prevents the GITHUB_TOKEN from persisting in .git/config, where subsequent steps could use it for unintended git operations.
  • Removed unused id-token: write from npm-dist-tag.yml, which authenticates via NPM_TOKEN secret, not OIDC.
  • Moved top-level permissions to job-level in release.yml and semantic-pull-request.yml, so each job's token scope is visible alongside its steps.

Supply chain hardening

  • SHA-pinned oven-sh/setup-bun (@v2 to @0c5077e..., v2.2.0), the only action still using a mutable tag. All actions across all workflows are now pinned to full commit SHAs.
  • Added zizmor security analysis workflow that runs on workflow file changes and uploads SARIF findings to the Security tab.
  • Added .github/zizmor.yml config to suppress 2 intentional findings: pull_request_target in semantic-pull-request.yml (no fork code is checked out) and cache-poisoning in release.yml (no caching is configured).

Injection prevention

  • Fixed template injection in npm-dist-tag.yml: inputs.package, inputs.version, and inputs.tag were interpolated directly in run:, which allows command injection if the input contains shell metacharacters. Moved all 3 to environment variables.
  • Fixed template injection in release.yml: steps.determine_npm_tag.outputs.npm_tag was interpolated in run:. Moved to an environment variable.

Validated locally

$ zizmor --gh-token="$(gh auth token)" --config .github/zizmor.yml .github/workflows/
34 findings (3 ignored, 21 suppressed): 1 informational, 0 low, 9 medium, 0 high

Summary by cubic

Hardened all GitHub Actions by defaulting to deny-all permissions: {} and granting minimal per‑job scopes. Also added zizmor security analysis, pinned the remaining floating action, fixed shell template injection in publish workflows, and made zizmor skip fork PRs to avoid SARIF upload failures.

  • Refactors

    • Default permissions: {} for every workflow; jobs now request only what they need (e.g., contents: read; release uses contents: write + id-token: write; semantic PR uses pull-requests: write).
    • Set persist-credentials: false on all actions/checkout; moved permissions to job-level in release.yml and semantic-pull-request.yml; removed unused id-token: write from npm-dist-tag.yml.
    • SHA-pinned oven-sh/setup-bun; all actions are now pinned to commit SHAs.
  • New Features

    • Added zizmor security analysis workflow that runs on workflow file changes, skips on fork PRs, and uploads SARIF to the Security tab.
    • Added .github/zizmor.yml to silence two intentional findings for pull_request_target and a cache false-positive.

Written for commit ef57065e47. Summary will update on new commits.


🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.

## 📋 Pull Request Information **Original PR:** https://github.com/better-auth/better-auth/pull/8879 **Author:** [@gustavovalverde](https://github.com/gustavovalverde) **Created:** 4/1/2026 **Status:** ✅ Merged **Merged:** 4/1/2026 **Merged by:** [@gustavovalverde](https://github.com/gustavovalverde) **Base:** `main` ← **Head:** `chore/harden-workflow-permissions` --- ### 📝 Commits (2) - [`0cb92e3`](https://github.com/better-auth/better-auth/commit/0cb92e32c7ff4f90c3691dfe10333b6cd7851e34) chore(ci): harden GitHub Actions workflow permissions - [`ef57065`](https://github.com/better-auth/better-auth/commit/ef57065e47d828e3bab1c17a7d9448b93cfec059) fix(ci): skip zizmor SARIF upload on fork PRs ### 📊 Changes **10 files changed** (+94 additions, -10 deletions) <details> <summary>View changed files</summary> 📝 `.github/workflows/ci.yml` (+11 -0) 📝 `.github/workflows/claude.yml` (+3 -0) 📝 `.github/workflows/demo.yml` (+5 -0) 📝 `.github/workflows/e2e.yml` (+12 -1) 📝 `.github/workflows/npm-dist-tag.yml` (+5 -3) 📝 `.github/workflows/preview.yml` (+5 -0) 📝 `.github/workflows/release.yml` (+7 -4) 📝 `.github/workflows/semantic-pull-request.yml` (+3 -2) ➕ `.github/workflows/zizmor.yml` (+31 -0) ➕ `.github/zizmor.yml` (+12 -0) </details> ### 📄 Description ## Summary Every workflow now follows a deny-all default: `permissions: {}` at the top level forces each job to declare only the permissions it actually needs. This eliminates the risk of compromised actions inheriting broad token access from repository defaults. The changes fall into 3 categories: access control, supply chain hardening, and injection prevention. ### Access control - **`permissions: {}` on all 9 workflows** (lock-threads already had it). Each job now declares its own minimal grant: `contents: read` for CI jobs, `contents: write` + `id-token: write` for the release job, `pull-requests: write` for the semantic PR validator. - **`persist-credentials: false` on all `actions/checkout` steps** (10 total). Prevents the GITHUB_TOKEN from persisting in `.git/config`, where subsequent steps could use it for unintended git operations. - **Removed unused `id-token: write`** from `npm-dist-tag.yml`, which authenticates via `NPM_TOKEN` secret, not OIDC. - **Moved top-level permissions to job-level** in `release.yml` and `semantic-pull-request.yml`, so each job's token scope is visible alongside its steps. ### Supply chain hardening - **SHA-pinned `oven-sh/setup-bun`** (`@v2` to `@0c5077e...`, v2.2.0), the only action still using a mutable tag. All actions across all workflows are now pinned to full commit SHAs. - **Added zizmor security analysis workflow** that runs on workflow file changes and uploads SARIF findings to the Security tab. - **Added `.github/zizmor.yml` config** to suppress 2 intentional findings: `pull_request_target` in `semantic-pull-request.yml` (no fork code is checked out) and `cache-poisoning` in `release.yml` (no caching is configured). ### Injection prevention - **Fixed template injection in `npm-dist-tag.yml`**: `inputs.package`, `inputs.version`, and `inputs.tag` were interpolated directly in `run:`, which allows command injection if the input contains shell metacharacters. Moved all 3 to environment variables. - **Fixed template injection in `release.yml`**: `steps.determine_npm_tag.outputs.npm_tag` was interpolated in `run:`. Moved to an environment variable. ### Validated locally ``` $ zizmor --gh-token="$(gh auth token)" --config .github/zizmor.yml .github/workflows/ 34 findings (3 ignored, 21 suppressed): 1 informational, 0 low, 9 medium, 0 high ``` <!-- This is an auto-generated description by cubic. --> --- ## Summary by cubic Hardened all GitHub Actions by defaulting to deny-all `permissions: {}` and granting minimal per‑job scopes. Also added zizmor security analysis, pinned the remaining floating action, fixed shell template injection in publish workflows, and made zizmor skip fork PRs to avoid SARIF upload failures. - **Refactors** - Default `permissions: {}` for every workflow; jobs now request only what they need (e.g., `contents: read`; release uses `contents: write` + `id-token: write`; semantic PR uses `pull-requests: write`). - Set `persist-credentials: false` on all `actions/checkout`; moved permissions to job-level in `release.yml` and `semantic-pull-request.yml`; removed unused `id-token: write` from `npm-dist-tag.yml`. - SHA-pinned `oven-sh/setup-bun`; all actions are now pinned to commit SHAs. - **New Features** - Added zizmor security analysis workflow that runs on workflow file changes, skips on fork PRs, and uploads SARIF to the Security tab. - Added `.github/zizmor.yml` to silence two intentional findings for `pull_request_target` and a cache false-positive. <sup>Written for commit ef57065e47d828e3bab1c17a7d9448b93cfec059. Summary will update on new commits.</sup> <!-- End of auto-generated description by cubic. --> --- <sub>🔄 This issue represents a GitHub Pull Request. It cannot be merged through Gitea due to API limitations.</sub>
GiteaMirror added the pull-request label 2026-04-15 22:45:03 -05:00
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#25174