Harden GitHub Actions workflows against token disclosure#6
Merged
Conversation
Applies the hardening pattern from laravel/fortify#674, in response to Composer CVE-2026-45793 (GitHub Actions GITHUB_TOKEN disclosure via Composer error messages, May 12-13 2026). - Pin every action to a commit SHA with a trailing version comment - Add top-level permissions blocks (deny-all by default in pint.yml, contents:read in test.yml) with least-privilege per job - Set persist-credentials: false on actions/checkout in test.yml. pint.yml keeps persist-credentials: true explicitly because git-auto-commit-action needs the token persisted to push lint fixes - Add .github/dependabot.yml so pinned SHAs stay current (monthly, grouped, labelled) - Add .github/CODEOWNERS so future .github/ changes require review - Broaden pint.yml branches-ignore to dependabot/** (was npm_and_yarn only) so Dependabot PRs do not trigger an auto-commit back
Auto-committing lint fixes from CI has two drawbacks worth avoiding: - Every contributor PR receives an extra commit attributed to the GITHUB_TOKEN identity, confusing review and breaking signed-commit policies. - Persisting credentials on actions/checkout (required by the git-auto-commit-action) widens the blast radius of any later step. Switching to `pint --test` makes the workflow fail on diff instead. Contributors run `composer pint` locally before pushing. - Drop the stefanzweifel/git-auto-commit-action dependency entirely (one less third-party action in the supply chain) - Set persist-credentials: false on the checkout (no push needed) - Drop the now-unused permissions: contents: write on the pint job; top-level permissions: contents: read is sufficient - Trigger on pull_request + push to main only (matches test.yml) - Drop the .env copy step (irrelevant for a library) - Simplify CODEOWNERS to a single repo-rooted entry
SRWieZ
added a commit
to knotsphp/system
that referenced
this pull request
May 18, 2026
- Pin every action to a commit SHA (with version comment) - Top-level permissions: contents: read on both workflows - persist-credentials: false on every actions/checkout - Switch pint to --test mode; drop git-auto-commit-action dependency - Add .github/dependabot.yml (monthly, grouped, labelled) - Add .github/CODEOWNERS so future .github/ changes need review Same pattern as knotsphp/publicip#6.
SRWieZ
added a commit
to knotsphp/flushdns
that referenced
this pull request
May 18, 2026
- Pin every action to a commit SHA (with version comment) - Top-level permissions: contents: read on both workflows - persist-credentials: false on every actions/checkout - Switch pint to --test mode; drop git-auto-commit-action dependency - Add .github/dependabot.yml (monthly, grouped, labelled) - Add .github/CODEOWNERS so future .github/ changes need review Same pattern as knotsphp/publicip#6.
SRWieZ
added a commit
to SRWieZ/php-svg-ps-converter
that referenced
this pull request
May 18, 2026
- Pin every action to a commit SHA (with version comment) - Top-level permissions: contents: read on both workflows - persist-credentials: false on every actions/checkout - Switch pint to --test mode; drop git-auto-commit-action dependency - Add .github/dependabot.yml (monthly, grouped, labelled) - Add .github/CODEOWNERS so future .github/ changes need review Same pattern as knotsphp/publicip#6.
SRWieZ
added a commit
to SRWieZ/queue-size-health-check
that referenced
this pull request
May 18, 2026
- Pin every action to a commit SHA (with version comment) - Top-level permissions: contents: read on both workflows - persist-credentials: false on every actions/checkout - Switch pint to --test mode; drop git-auto-commit-action dependency - Add .github/dependabot.yml (monthly, grouped, labelled) - Add .github/CODEOWNERS so future .github/ changes need review Same pattern as knotsphp/publicip#6.
SRWieZ
added a commit
to SRWieZ/php-starlink-client
that referenced
this pull request
May 18, 2026
- Pin every action to a commit SHA (with version comment) - Top-level permissions: contents: read on both workflows - persist-credentials: false on every actions/checkout - Switch pint to --test mode; drop git-auto-commit-action dependency - Add .github/dependabot.yml (monthly, grouped, labelled) - Add .github/CODEOWNERS so future .github/ changes need review Same pattern as knotsphp/publicip#6.
SRWieZ
added a commit
to SRWieZ/grpc-protoset
that referenced
this pull request
May 19, 2026
- Pin every action to a commit SHA (with version comment) - Top-level permissions: contents: read on both workflows - persist-credentials: false on every actions/checkout - Switch pint to --test mode; drop git-auto-commit-action dependency - Add .github/dependabot.yml (monthly, grouped, labelled) - Add .github/CODEOWNERS so future .github/ changes need review Same pattern as knotsphp/publicip#6.
SRWieZ
added a commit
to SRWieZ/thumbhash
that referenced
this pull request
May 19, 2026
* Harden GitHub Actions workflows against token disclosure - Pin every action to a commit SHA (with version comment) - Top-level permissions: contents: read - persist-credentials: false on actions/checkout - Add .github/dependabot.yml (monthly, grouped, labelled) - Add .github/CODEOWNERS so future .github/ changes need review Same pattern as knotsphp/publicip#6. * Skip --display-deprecations on PHP 8.1 Pest resolves to a version using PHPUnit 9.x on PHP 8.1 (Pest 3.x requires PHP 8.2+), and PHPUnit 9 does not support --display-deprecations. Group PHP 8.1 with the no-flag run instead.
SRWieZ
added a commit
to SRWieZ/forge-heartbeats
that referenced
this pull request
May 19, 2026
* Harden GitHub Actions workflows against token disclosure
- Pin every action to a commit SHA (with version comment)
- Top-level permissions: contents: read on tests.yml and static-analysis.yml;
permissions: {} on update-changelog.yml (deny-all top, contents: write job)
- persist-credentials: false on every actions/checkout in tests.yml and
static-analysis.yml; explicit persist-credentials: true on
update-changelog.yml (git-auto-commit-action needs it to push CHANGELOG)
- Add .github/dependabot.yml (monthly, grouped, labelled)
- Add .github/CODEOWNERS so future .github/ changes need review
Same pattern as knotsphp/publicip#6.
* Drop Laravel 10 from test matrix
saloonphp/laravel-plugin ^4.0 (current composer.json constraint)
requires illuminate/console ^11.0, which is incompatible with Laravel 10.
Composer cannot resolve any Laravel 10 cell in the matrix; those jobs
have been red on main since 2026-03-30.
If Laravel 10 support is desired, loosen the saloonphp constraint in
composer.json — separate change.
* Revert "Drop Laravel 10 from test matrix"
This reverts commit 081b266.
* Support saloonphp v3 and v4
Widen the saloonphp/laravel-plugin and saloonphp/saloon constraints
to ^3.0 || ^4.0. This restores Laravel 10 support (saloon v4 dropped
Laravel 10) without forcing existing v3 users to upgrade.
All Saloon symbols used by this package (Connector, Request, Response,
SoloRequest, TokenAuthenticator, Method, HasBody, HasJsonBody,
AcceptsJson, RequestException) are stable across v3.0+ and v4.0+.
The CI matrix exercises both prefer-lowest (saloon v3) and prefer-stable
(saloon v4) across Laravel 10/11/12, so a regression on either major
will be caught.
This was referenced May 19, 2026
SRWieZ
added a commit
to SRWieZ/php-bin-with-grpc
that referenced
this pull request
May 19, 2026
- Pin every action to a commit SHA (with version comment)
- Top-level permissions: {} (deny-all) on both workflows; least-privilege
job-level permissions
- build-php.yml: drop the top-level env: GITHUB_TOKEN block (over-broad,
exposed the token to every step incl. third-party SPC binary).
peter-evans/create-pull-request picks up GITHUB_TOKEN via its own
token input default (github.token)
- update-ca-file.yml: replace deprecated/archived actions/create-release@v1
with softprops/action-gh-release (SHA-pinned)
- persist-credentials: false on the build-php checkout (peter-evans uses
its own token-based auth, not .git/config). update-ca-file.yml keeps
persist-credentials: true explicitly because the workflow runs `git push`
directly in shell to commit the CA file refresh
- Add .github/dependabot.yml (monthly, grouped, labelled)
- Add .github/CODEOWNERS so future .github/ changes need review
Same pattern as knotsphp/publicip#6.
Pre-existing bugs left untouched (worth a separate PR):
- update-ca-file.yml `release` job's `if:` references
`needs.fetch-ca-file.outputs.changed`, but `fetch-ca-file` has no
`outputs:` block — the conditional is always false, so the release
job has never run.
- The same job references `steps.latestrelease.outputs.version`, but
the curl in `latestrelease` assigns to a local bash var, never to
GITHUB_OUTPUT.
This was referenced May 19, 2026
SRWieZ
added a commit
to SRWieZ/svgtinyps-cli
that referenced
this pull request
May 19, 2026
- Pin every action to a commit SHA (with version comment): checkout,
cache, setup-php, upload-artifact, action-gh-release across all 8
workflows
- Top-level permissions: {} (deny-all) on all 6 build-* workflows;
contents: read on test.yml and pint.yml. Job-level contents: write
only on the build jobs that need to upload release assets
- Drop the top-level env: GITHUB_TOKEN block from each build-* workflow
(it exposed the token to every step, incl. the static-PHP build
scripts). softprops/action-gh-release picks up github.token via its
`token` input default
- persist-credentials: false on every actions/checkout (no workflow
pushes to git; softprops uses GITHUB_TOKEN env via the REST API)
- pint.yml: switch from `composer pint` (fix mode, no-op in CI) to
`vendor/bin/pint --test` so lint issues actually fail the build.
Narrow trigger to pull_request + push to main (was every push minus
one specific dependabot prefix)
- Add .github/dependabot.yml (monthly, grouped, labelled)
- Add .github/CODEOWNERS so future .github/ changes need review
Same pattern as knotsphp/publicip#6.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Why
Composer CVE-2026-45793 (disclosed 2026-05-13) leaked GitHub Actions
GITHUB_TOKENvalues into stderr during a ~14-hour window when Composer's token-format validator rejected GitHub's newghs_<id>_<base64url-JWT>token format and printed the rejected token verbatim. GitHub's secret masker couldn't reliably redact those tokens once Symfony Console wrapped or framed them with ANSI codes.The audit of this repo found no workflow runs in the affected window (2026-05-12 → 2026-05-13), so no logs need scrubbing. This PR is forward-looking hardening, applying the pattern Laravel just merged in laravel/fortify#674.
What this PR changes
1. Pin every action to a commit SHA (with trailing version comment)
Tags are mutable — a maintainer-account compromise or a force-pushed
@v2tag (cf. tj-actions/changed-files, CVE-2025-30066) silently re-routes your workflow to attacker-controlled code on the next run. SHAs are immutable.actions/checkout34e114876b0b11c390a56381ad16ebd13914f8d5(v4.3.1)shivammathur/setup-php7c071dfe9dc99bdf297fa79cb49ea005b9fcadbc(v2.37.1)actions/cache0057852bfaa89a56745cba8c7296529d2fc39830(v4.3.0)2. Top-level
permissions: contents: readon both workflows. No job needs more.3.
persist-credentials: falseon everyactions/checkout. No workflow pushes, so no credentials need to survive checkout.4. Switch pint workflow to
--testmode (was auto-commit)Previously pint ran on every push and committed lint fixes back via
stefanzweifel/git-auto-commit-action. That pattern has two drawbacks:GITHUB_TOKENidentity — confusing for review, breaks signed-commit policies.The new pint workflow runs
vendor/bin/pint --test, fails on diff, and asks contributors to runcomposer pintlocally. Thestefanzweifel/git-auto-commit-actiondependency is dropped entirely (one less third-party action in the supply chain).Trigger narrowed from "every push" to
pull_request + push to main + workflow_dispatchto matchtest.yml.5.
.github/dependabot.ymlso pinned SHAs don't rotpatterns: ["*"]) so all action bumps land in a single PR per month.dependencies,cifor easy triage.6.
.github/CODEOWNERS—@SRWieZowns/.github/so future workflow changes require maintainer review.A note on the second commit (48e41a9)
When this branch was first pushed, the old auto-commit pint workflow was still in effect and ran one last time — it found a tiny pre-existing lint debt in
cli/publicip.php(2 lines) and committed the fix as48e41a9. That fix is legitimate. Subsequent pushes to this branch no longer auto-commit because the new pint triggers only onpull_requestandpush: main.What this PR does not change
tools: composer:v2already pulls latest 2.x (2.9.8+), which contains the CVE fix. No explicit pin needed.Repo-level settings still to apply (separately, outside this PR)
v*so a stolen token cannot push a malicious release tag.mainrequiring CODEOWNERS approval on.github/**.GITHUB_TOKENpermissions at repo level set to read-only (forces every workflow to explicitly opt in to writes).Happy to apply these via
gh apiafter this PR merges.Test plan
Testsworkflow green on this PR (3 OS × 2 PHP = 6 cells).Lintingworkflow green on this PR (Pint reports no diff after the auto-fix in 48e41a9).References