Credential Security Improvements in checkout v6: How Token Storage Changed
actions/checkout v6 stores authentication tokens in a temporary file under $RUNNER_TEMP instead of writing them directly to .git/config, using Git's includeIf mechanism to scope credentials to specific directories and minimize exposure.
The actions/checkout v6 release introduces significant credential security improvements that fundamentally change how GitHub tokens persist across your workflow jobs. Instead of embedding sensitive authentication data within your repository's .git directory, the action now isolates credentials in temporary storage with strict access controls. This article examines the specific security enhancements implemented in the actions/checkout repository to help you understand the protection mechanisms and configuration options available.
Isolated Credentials File Storage
The most significant change in checkout v6 moves the personal access token (PAT) out of the repository's metadata. When persist-credentials is enabled, the token is written to a temporary file under $RUNNER_TEMP rather than directly into .git/config. This limits exposure of the token to the workspace and makes cleanup more reliable when the job completes.
According to the repository's README (lines 15-18), this change ensures that sensitive credentials remain outside the persisted workspace, reducing the risk of accidental exposure through repository artifacts or logs.
Scoped Access with Git Include-If
To prevent the token from being used for unrelated Git operations on the runner, the temporary credentials file is referenced via Git's includeIf feature. This mechanism ensures the token is only available for the specific repository directory (or worktree) and not for any other Git commands executed during the job.
In src/git-auth-helper.ts (lines 60-78), the helper creates the credentials configuration and adds includeIf.gitdir:<path>.path entries that bind the temporary file to the specific repository path:
// Inside src/git-auth-helper.ts – creation of the temporary credentials file
private credentialsConfigPath = '' // ← path under $RUNNER_TEMP
...
await this.git.config(this.tokenConfigKey, this.tokenPlaceholderConfigValue, false, false, credentialsConfigPath)
...
content = content.replace(this.tokenPlaceholderConfigValue, this.tokenConfigValue)
await fs.promises.writeFile(credentialsConfigPath, content)
await this.git.config('includeIf.gitdir:${gitDir}.path', credentialsConfigPath)
Placeholder Protection Against Audit Logs
To evade process-creation audit events that might capture command arguments or environment variables, the action implements a placeholder mechanism. Before the real token is written, a placeholder value (AUTHORIZATION: basic ***) is stored in the configuration. The placeholder is later replaced inside the temporary file with the actual token, ensuring the credential never appears in process logs.
This handling occurs in the configureToken method within src/git-auth-helper.ts (lines 33-57), providing an additional layer of defense against credential leakage through system monitoring tools.
Docker Container Support
The credential security improvements extend to Docker-based workflows. The action adds separate includeIf entries for the container's $HOME path (/github/runner_temp), ensuring the token remains accessible when checkout runs inside a Docker container.
In configureSubmoduleAuth (lines 66-78 of src/git-auth-helper.ts), the implementation handles both the host runner environment and the container-specific configuration paths, maintaining security isolation across different execution contexts.
Configuration and Opt-Out Options
Users retain full control over credential persistence. While the new behavior is the default when persist-credentials is set to true (the default value), you can explicitly opt out to preserve the legacy behavior.
The input is parsed in src/input-helper.ts (lines 66-70), allowing you to disable the temporary file storage:
# Typical usage – credentials are persisted in a safe temporary file
- uses: actions/checkout@v6
with:
persist-credentials: true # default; stores token in $RUNNER_TEMP
# Opt‑out – fall back to the older behaviour (token written to .git/config)
- uses: actions/checkout@v6
with:
persist-credentials: false
Setting persist-credentials: false prevents the action from writing the token to either the temporary file or .git/config, which is useful when subsequent steps do not require authenticated Git operations.
Summary
- Temporary file storage: Credentials are stored in
$RUNNER_TEMPinstead of.git/config, limiting exposure to the workspace - Directory-scoped access: Git's
includeIfmechanism ensures tokens are only used for the specific repository directory - Audit log protection: Placeholder values prevent real tokens from appearing in process-creation audit events
- Container compatibility: Separate configuration paths support Docker-based actions without compromising security
- Explicit opt-out: The
persist-credentials: falseinput preserves legacy behavior when required
Frequently Asked Questions
Where does checkout v6 store the GitHub token?
When persist-credentials is enabled, checkout v6 stores the GitHub token in a temporary file under $RUNNER_TEMP rather than writing it directly to .git/config. The location is referenced via Git's includeIf configuration to ensure the token is only loaded for operations within the specific repository directory.
How does the placeholder mechanism protect credentials?
The action first writes a placeholder value (AUTHORIZATION: basic ***) to the configuration file before replacing it with the actual token. This prevents process-creation audit events and system monitoring tools from capturing the real credential during the initial file write operation, as implemented in src/git-auth-helper.ts.
Can I revert to the old credential storage behavior?
Yes, set persist-credentials: false in your workflow configuration to disable the temporary file storage and return to the legacy behavior of writing tokens directly to .git/config. This input is parsed in src/input-helper.ts (lines 66-70).
Does this work with self-hosted runners and Docker containers?
Yes, the implementation in src/git-auth-helper.ts (lines 66-78) adds separate includeIf entries for container-specific paths such as /github/runner_temp, ensuring that credentials remain accessible and secure when the checkout action runs inside Docker containers or on self-hosted runners with custom environments.
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 →