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.
# .github/workflows/build.yml: ❌ Token shipped inside the artifactjobs: 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# .github/workflows/build.yml: ✅ Either fix closes itjobs: 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: trueSee the CLI documentation for the full configuration reference.