Describe the problem
Two CI/CD hygiene improvements that follow the principle of least privilege:
1. Persisted git credentials (persist-credentials: true default)
All actions/checkout usages retain the default persist-credentials: true, which writes the GITHUB_TOKEN into .git/config as a base64-encoded HTTP extraheader. This token remains readable by any process for the entire workflow run. The most sensitive instances are:
- Release workflow (
release.yml): Token has contents: write, id-token: write, and pull-requests: write permissions, plus npm publishing access
- Autofix workflow (
autofix-lint.yml): Token has contents: write and is exposed to pnpm install, pnpm format, and code generation steps
After checkout, any subsequent step can extract the token:
grep -A1 'extraheader' .git/config
# AUTHORIZATION: basic <base64-encoded-token>
2. Over-broad secret inheritance in platform tests
The platform-tests-all.yml workflow passes all repository-level secrets to the Vercel tests workflow via secrets: inherit, when only three specific secrets are needed (VERCEL_TOKEN, VERCEL_PROJECT_ID_BASIC, VERCEL_ORG_ID). Any repository-level secrets added in the future will automatically become accessible without explicit review.
# Current
jobs:
vercel:
uses: ./.github/workflows/platform-tests-vercel.yml
secrets: inherit # passes ALL repository secrets
Describe the proposed solution
For persisted credentials, add persist-credentials: false to all actions/checkout usages:
- uses: actions/checkout@v6
with:
persist-credentials: false
For workflows that need to push commits (like autofix-lint.yml), configure git authentication explicitly only for the push step and unset it immediately after:
- name: Push changes
run: |
git config --local http.https://github.com/.extraheader \
"AUTHORIZATION: basic $(echo -n x-access-token:${{ github.token }} | base64)"
git push origin HEAD
git config --local --unset http.https://github.com/.extraheader
For secret inheritance, replace secrets: inherit with explicit secret passing:
jobs:
vercel:
uses: ./.github/workflows/platform-tests-vercel.yml
with:
sha: ${{ inputs.sha }}
secrets:
VERCEL_TOKEN: ${{ secrets.VERCEL_TOKEN }}
VERCEL_PROJECT_ID_BASIC: ${{ secrets.VERCEL_PROJECT_ID_BASIC }}
VERCEL_ORG_ID: ${{ secrets.VERCEL_ORG_ID }}
Alternatives considered
- Relying on GitHub's token expiration (tokens expire after the workflow run) — but within a single run, the token is available to all steps regardless of whether they need it.
- Using environment-scoped secrets exclusively — this helps for the platform tests case but doesn't address the persisted credentials issue.
Importance
would make my life easier
Additional Information
Affected workflows:
ci.yml — multiple checkout instances (contents: read, lower risk)
autofix-lint.yml — checkout with contents: write
release.yml — checkout with contents: write, id-token: write, pull-requests: write
platform-tests-vercel.yml — checkout with contents: read
audit.yml — checkout with contents: read
platform-tests-all.yml — secrets: inherit to called workflow
These changes complement SHA-pinning of third-party actions as general CI/CD hardening best practices.
Describe the problem
Two CI/CD hygiene improvements that follow the principle of least privilege:
1. Persisted git credentials (
persist-credentials: truedefault)All
actions/checkoutusages retain the defaultpersist-credentials: true, which writes theGITHUB_TOKENinto.git/configas a base64-encoded HTTP extraheader. This token remains readable by any process for the entire workflow run. The most sensitive instances are:release.yml): Token hascontents: write,id-token: write, andpull-requests: writepermissions, plus npm publishing accessautofix-lint.yml): Token hascontents: writeand is exposed topnpm install,pnpm format, and code generation stepsAfter checkout, any subsequent step can extract the token:
2. Over-broad secret inheritance in platform tests
The
platform-tests-all.ymlworkflow passes all repository-level secrets to the Vercel tests workflow viasecrets: inherit, when only three specific secrets are needed (VERCEL_TOKEN,VERCEL_PROJECT_ID_BASIC,VERCEL_ORG_ID). Any repository-level secrets added in the future will automatically become accessible without explicit review.Describe the proposed solution
For persisted credentials, add
persist-credentials: falseto allactions/checkoutusages:For workflows that need to push commits (like
autofix-lint.yml), configure git authentication explicitly only for the push step and unset it immediately after:For secret inheritance, replace
secrets: inheritwith explicit secret passing:Alternatives considered
Importance
would make my life easier
Additional Information
Affected workflows:
ci.yml— multiple checkout instances (contents: read, lower risk)autofix-lint.yml— checkout withcontents: writerelease.yml— checkout withcontents: write,id-token: write,pull-requests: writeplatform-tests-vercel.yml— checkout withcontents: readaudit.yml— checkout withcontents: readplatform-tests-all.yml—secrets: inheritto called workflowThese changes complement SHA-pinning of third-party actions as general CI/CD hardening best practices.