Skip to main content
ISSUE-310HighQuickCLICI/CD Secrets

Persisted checkout credentials packed into an uploaded artifact

Control: Checkout must not persist credentials· Config key: checkoutMustNotPersistCredentials

📋 What is this?

A job runs actions/checkout with credential persistence enabled and a later actions/upload-artifact step uploads a .git-inclusive path — the workspace root, ., or any path naming .git.

⚠️ Impact

The GITHUB_TOKEN written into .git/config is packed into the artifact, which is downloadable — anonymously on public repositories. This is the canonical 'ArtiPACKED' leak: unlike ISSUE-307, the credential does not merely linger, it leaves the job.

🔧 How to fix

Set persist-credentials: false on the actions/checkout step, or upload a scoped path that excludes .git (path: dist/ rather than path: .). Either one alone closes it.

✗ BeforeAnyone who can download the artifact reads the workflow's GITHUB_TOKEN out of .git/config.
# .github/workflows/build.yml: ❌ Token shipped inside the artifact
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4 # persist-credentials defaults to true
- run: ./build.sh
- uses: actions/upload-artifact@v4
with:
path: . # the workspace root includes .git/config
✓ AfterNo credential in .git/config, and the artifact is scoped to build output.
# .github/workflows/build.yml: ✅ Either fix closes it
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@11bd71901bbe5b1630ceea73d27597364c9af683 # v4.2.2
with:
persist-credentials: false
- run: ./build.sh
- uses: actions/upload-artifact@26f96dfa697d77e81fd5907df203aa23a56210a8 # v4.3.0
with:
path: dist/ # scoped, no .git

💡 Tips

  • Scoping the upload path is the more durable fix: it also keeps build artifacts free of source history and secrets files.
  • If a later step must push back, set the remote URL explicitly with a scoped token rather than relying on the checkout's persisted credential.

⚙️ Configuration

This control is configured in .plumber.yaml under the github section:

github:
  controls:
    checkoutMustNotPersistCredentials:
      enabled: true

See the CLI documentation for the full configuration reference.