How the persist-credentials Input Affects Git Authentication in actions/checkout

The persist-credentials input determines whether the GitHub Actions runner retains the authentication token or SSH key in the local Git configuration after the checkout step finishes, defaulting to true to allow subsequent steps to reuse credentials for private repository access.

The actions/checkout repository provides this boolean input to balance convenience against security hygiene in CI/CD workflows. When enabled, the action writes the provided token or SSH key into Git config files and temporary credential stores that persist for the remainder of the job. When disabled, the action immediately purges these configurations after the initial clone or fetch completes, limiting the window of exposure for sensitive authentication material.

How persist-credentials Works

The input is defined in action.yml with a default value of true. Internally, the flag is read in src/input-helper.ts (lines 167-169) and stored in the IGitSourceSettings interface defined in src/git-source-settings.ts. The actual behavioral split occurs in src/git-source-provider.ts and src/git-auth-helper.ts, where the action either preserves or removes Git authentication configurations based on this setting.

Default Behavior (persist-credentials: true)

When persist-credentials is set to true (the default), the checkout action performs the following:

  • Writes the authentication token or SSH key into the local Git configuration (src/git-auth-helper.ts, lines 161-168)
  • Creates a temporary credentials configuration file and adds includeIf.gitdir: entries so that Git commands executed inside Docker containers can access the same authentication (src/git-source-provider.ts, lines 291-296)
  • Leaves these configurations intact after the checkout step completes, allowing subsequent workflow steps to interact with private repositories or fetch additional refs without re-authenticating

This persistence is particularly important for workflows that fetch private submodules. The action specifically handles submodule authentication by preserving credentials when settings.persistCredentials evaluates to true in src/git-source-provider.ts.

Non-Persistent Mode (persist-credentials: false)

Setting persist-credentials: false triggers a cleanup routine immediately after the checkout completes:

  • The action removes all authentication configurations from the Git config, including the core.sshCommand settings and token-based helpers (src/git-source-provider.ts, lines 319-321)
  • The temporary credentials file is deleted and includeIf entries are stripped, ensuring no residual secrets remain on the runner
  • Subsequent Git commands that require authentication (such as fetching private branches or submodules) will fail unless explicitly provided with fresh credentials

In src/git-auth-helper.ts, the logic that configures core.sshCommand and writes temporary credential files is skipped entirely when the persist flag is disabled.

Security Implications and Submodule Behavior

The choice between persistent and non-persistent credentials carries significant security and functionality tradeoffs.

Security Boundary: When persist-credentials is enabled, the authentication token remains in the global Git configuration and environment variables for all subsequent steps in the job. Any compromised action or malicious script running later in the workflow could exfiltrate this token. Setting the input to false constrains the credential lifetime strictly to the checkout action itself.

Private Submodules: Workflows cloning private submodules generally require persist-credentials: true. The action uses the preserved token to configure submodule authentication via includeIf.gitdir: directives. Without persistence, submodule fetch operations fail because the temporary credentials are removed before the submodule initialization step executes.

Container Jobs: For jobs running inside Docker containers, the action writes a container-side include path (typically under /github/runner_temp/) only when persistence is enabled. This ensures Git processes inside the container can access the token, but it also extends the credential exposure into the container environment.

Configuration Examples

Basic Usage with Default Persistence

The default configuration leaves credentials active for later steps:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout with default persistence
        uses: actions/checkout@v4
        with:
          token: ${{ secrets.PAT }}
          # persist-credentials defaults to true

      - name: Use token in a later step
        run: |
          git fetch origin private-branch

The git fetch succeeds because the Personal Access Token remains in the repository's Git config.

Disabling Credential Persistence

To remove authentication immediately after checkout:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout without persisting credentials
        uses: actions/checkout@v4
        with:
          token: ${{ secrets.PAT }}
          persist-credentials: false

      - name: Attempt private fetch
        run: |
          git fetch origin private-branch || echo "fetch failed as expected"

The subsequent fetch fails because src/git-source-provider.ts has already executed its cleanup block (lines 319-321), removing the token from the configuration.

Private Submodules with Persistence

When fetching private submodules, persistence is required:

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checkout repo with private submodule
        uses: actions/checkout@v4
        with:
          submodules: recursive
          persist-credentials: true

      - name: Verify submodule fetched
        run: |
          git -C path/to/submodule status

Without persist-credentials: true, the submodule fetch would fail because the temporary credentials configured in src/git-auth-helper.ts would be unavailable during the recursive clone operation.

Source Code Architecture

The implementation spans several TypeScript files in the repository:

  • src/input-helper.ts (lines 167-169): Reads the persist-credentials input from the workflow and assigns it to result.persistCredentials
  • src/git-source-settings.ts: Defines the persistCredentials boolean in the IGitSourceSettings interface
  • src/git-auth-helper.ts (lines 161-168): Conditionally configures token and SSH authentication based on the persistCredentials setting
  • src/git-source-provider.ts (lines 291-296, 319-321): Handles the persistence logic for submodules and executes the cleanup routine when persistence is disabled
  • action.yml: Declares the input with its default value and documentation

Summary

  • The persist-credentials input in actions/checkout defaults to true, leaving authentication tokens in the Git config after checkout
  • When set to false, the action removes all credential configurations immediately after the initial clone, as implemented in src/git-source-provider.ts
  • Private submodules require persist-credentials: true to fetch successfully because the action relies on persistent includeIf configurations
  • Security-conscious workflows should disable persistence to prevent credential exposure to subsequent steps, though this requires manual authentication for later Git operations
  • The implementation spans src/input-helper.ts, src/git-auth-helper.ts, and src/git-source-provider.ts, with conditional logic based on the IGitSourceSettings.persistCredentials boolean

Frequently Asked Questions

What happens to the Git token when persist-credentials is set to false?

When persist-credentials is set to false, the actions/checkout repository removes the authentication token from the Git configuration immediately after the initial checkout completes. According to the source code in src/git-source-provider.ts (lines 319-321), the cleanup block executes before the action finishes, deleting temporary credential files and removing core.sshCommand configurations that the token relies upon.

Can I fetch private submodules if persist-credentials is false?

No, fetching private submodules will fail if persist-credentials is set to false. The action configures submodule authentication using temporary credential files and includeIf.gitdir: directives in src/git-auth-helper.ts (lines 161-168) only when persistence is enabled. Without these preserved configurations, the subsequent submodule fetch operations lack authentication credentials.

Does persist-credentials affect SSH key authentication as well as tokens?

Yes, the persist-credentials input controls both HTTPS token-based authentication and SSH key authentication. In src/git-auth-helper.ts, the logic that sets core.sshCommand to use a specific SSH key respects the settings.persistCredentials flag. When disabled, the action skips configuring the SSH command, and any SSH-based Git operations in subsequent steps will fail unless the runner has independent SSH agent access.

Is it safe to leave persist-credentials set to true?

Leaving persist-credentials set to true is convenient but increases the attack surface. The token remains in the Git configuration and environment for all subsequent workflow steps, meaning any compromised action or injection vulnerability could potentially access the credential. For high-security environments or workflows that do not need subsequent Git operations, GitHub recommends setting persist-credentials: false to minimize the credential exposure window.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →