Understanding the Credential Security Model in actions/checkout v6+
Starting with version 6, actions/checkout isolates authentication tokens in temporary files under $RUNNER_TEMP instead of writing them to .git/config, leveraging Git includeIf directives and automatic cleanup to prevent credential leakage.
The actions/checkout action is the official GitHub Action for cloning repositories into workflow runners. Beginning with version 6, the credential security model in actions/checkout v6+ was fundamentally redesigned to eliminate direct storage of sensitive tokens in the repository's persistent Git configuration, significantly reducing the attack surface for "pwn-request" style vulnerabilities.
Temporary Credentials File Architecture
Rather than embedding secrets directly into .git/config, the action creates a temporary credentials file inside the runner’s $RUNNER_TEMP directory.
UUID-Based Path Generation
The action generates a unique path for each run to prevent collisions and predictable file locations. In src/git-auth-helper.ts, the getCredentialsConfigPath() method constructs a file named git-credentials-<uuid>.config (lines 16-28). This ensures that even if the runner is shared or compromised during execution, the credential file path cannot be guessed by other processes.
Placeholder-to-Token Replacement Strategy
To avoid exposing the real token in process listings or temporary file metadata during creation, the action implements a two-phase write process. First, it writes a placeholder string AUTHORIZATION: basic *** to the temporary file (lines 63-65). Immediately after file creation, it replaces the placeholder with the actual Base64-encoded token in the format x-access-token:<PAT> (lines 44-58). This minimizes the window where sensitive material exists in cleartext on disk.
Git includeIf Scoping and Isolation
The action registers the temporary credentials file with Git using conditional configuration directives rather than global settings.
For the primary checkout repository, src/git-auth-helper.ts adds an includeIf.gitdir:<repo-path>.path entry that points to the temporary file (lines 70-84). Similar entries are configured for work-tree and container paths when applicable. This scopes the token to the checkout only, ensuring that Git uses the credentials solely for operations within the designated repository path without polluting the global Git configuration or affecting other repositories on the runner.
Automatic Cleanup and Persistence Controls
The security model ensures credentials do not persist beyond the job lifecycle through explicit cleanup routines and user-configurable persistence settings.
Post-Job Cleanup Mechanism
The removeToken() function (lines 72-78 in src/git-auth-helper.ts) executes during the post-job phase to delete the temporary credentials file. This guarantees that the secret never remains on the runner after the step finishes, even if the runner is reused for subsequent jobs or remains idle.
Controlling Credential Persistence
Users can control this behavior via the persist-credentials input, which defaults to true. When set to false (as defined in src/input-helper.ts at line 168), the action skips the includeIf registration step entirely. In this mode, the token is available only for the initial checkout operation and is not retained for later Git commands such as git push or git fetch.
SSH Authentication Handling
The temporary file model extends to SSH authentication. When an SSH key is supplied, the action writes it to a temporary file under $RUNNER_TEMP, builds a GIT_SSH_COMMAND environment variable, and optionally stores core.sshCommand in the temporary Git configuration when persist-credentials is enabled (lines 50-60 in src/git-auth-helper.ts). All temporary SSH material is subsequently removed via the removeSsh() cleanup function.
Practical Configuration Examples
The following configurations demonstrate the credential security model in practice:
# Standard checkout with credentials persisted for later git commands
- uses: actions/checkout@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
persist-credentials: true
# Checkout without persisting credentials (one-off fetch only)
- uses: actions/checkout@v6
with:
token: ${{ secrets.GITHUB_TOKEN }}
persist-credentials: false
When persist-credentials: false, only the initial clone and fetch operations are authenticated. Any subsequent git push, git fetch, or submodule operations will fail unless you provide an alternative authentication method.
Summary
- actions/checkout v6+ stores authentication tokens in temporary files under
$RUNNER_TEMPrather than in.git/config. - The
GitAuthHelperclass generates unique credential paths and uses placeholder swapping to minimize token exposure during file creation. - Git
includeIfdirectives scope credentials to specific repository paths, preventing cross-repository access. - The
removeToken()andremoveSsh()functions ensure automatic cleanup of all temporary authentication material in the post-job phase. - The
persist-credentialsinput allows workflows to opt out of credential retention entirely when only the initial checkout requires authentication.
Frequently Asked Questions
How does actions/checkout v6+ store credentials differently from previous versions?
Previous versions wrote tokens directly into the repository's .git/config file, leaving credentials on disk in the workspace. Version 6+ writes to temporary files outside the workspace and uses Git includeIf directives to reference them, ensuring credentials are isolated from the repository directory and automatically removed after the job.
What happens to the temporary credential file after the job completes?
The removeToken() function executes automatically during the post-job cleanup phase (defined in src/git-auth-helper.ts), deleting the temporary credentials file from $RUNNER_TEMP. This ensures the secret is not left behind on self-hosted runners or reusable workflow environments.
Can I prevent credentials from persisting for subsequent steps?
Yes. Set persist-credentials: false in the action inputs. According to the source code in src/input-helper.ts (line 168), this skips the includeIf configuration step, meaning the token is used only for the initial checkout and is immediately unavailable for any subsequent Git operations within the same job.
How are SSH keys handled in this security model?
SSH keys follow the same temporary file pattern. The action writes keys to a temporary location under $RUNNER_TEMP, configures GIT_SSH_COMMAND and core.sshCommand to use them, and invokes removeSsh() during cleanup to delete the material. This mirrors the HTTP credential approach, ensuring SSH private keys never persist in environment variables or configuration files beyond the job duration.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →