Skip to main content
RunBook Academy

Git, CI/CD & GitOpsXXVI · Git ConfigurationGitConfig

Credential helpers and secure storage — what each one stores, where, and at what risk

Intermediate⏱ ~20 mingit

What you'll learn

  • Explain how credential.helper delegates password retrieval to an external program
  • Compare the security properties of cache, store, osxkeychain, wincred, manager, and libsecret
  • Recognise the security trade-off between plaintext storage and OS-provided secure storage
  • Choose the right helper for a workstation, a shared runner, and a CI job

Prerequisites

Verified against Git 2.55.x teaching target; 2.40+ minimum · GitHub Actions continuous service; Aug 2026 documentation baseline · Argo CD v3.5.x teaching target; v3.0+ minimum · Flux v2.9.x · Sigstore Cosign v3.1.x · SLSA v1.2 · OCI Distribution Specification v1.1 · Git LFS v3.7.1 · Kubernetes (cross-course target) 1.36.x

Not yet marked complete on this device.

credential.helper names a program Git invokes to fetch, store, or erase credentials for an HTTP or HTTPS remote. Git ships with several helpers and supports third-party ones; each helper implements the same protocol but stores the credential in a different place. The choice of helper is the choice of where the credential lives, and where the credential lives is the choice of who can read it.

The credential-helper protocol

A credential helper is a program. Git invokes it with a verb (get, store, erase) on the command line and writes a list of key-value lines to the helper’s stdin:

protocol=https
host=github.com
username=alice

The helper reads the lines, looks up (or stores, or erases) a matching credential, and writes the result to stdout in the same format. Git then uses the returned credential to authenticate the next HTTPS request. This protocol is what every helper implements; the difference between helpers is the backend.

flowchart LR
    A["git push"] --> B{"need credential?"}
    B -->|no| C["push proceeds"]
    B -->|yes| D["git invokes helper 'get'"]
    D --> E{"helper backend"}
    E -->|cache| F["in-memory for N seconds"]
    E -->|store| G["plaintext file on disk"]
    E -->|osxkeychain| H["macOS Keychain"]
    E -->|wincred| I["Windows Credential Manager"]
    E -->|manager| J["cross-platform secure store"]
    E -->|libsecret| K["Linux Secret Service (GNOME Keyring)"]
    F --> L["credential returned"]
    G --> L
    H --> L
    I --> L
    J --> L
    K --> L
    L --> M["git uses credential"]

The built-in helpers

Git’s source tree includes several helpers, each with a different backend and a different threat model:

  • cache keeps credentials in memory for a configurable timeout (default 900 seconds). The credential never touches disk. The risk is that the memory is the process’s memory; a core dump or a debugger attach can read it. Use cache on a developer workstation where the threat is “the credential sits in ~/.git-credentials for years” and the gain is “the credential disappears when I reboot”.
  • store writes credentials to a plaintext file (typically ~/.git-credentials). The file is the credential. The risk is the file: any process running as the user can read it, any backup copies it, any disk image contains it. Store is the helper that produces “credentials on a USB stick” incidents.
  • osxkeychain (macOS) stores credentials in the user’s login keychain. The keychain is encrypted at rest with the user’s login password and is unlocked when the user logs in. The risk is the keychain’s threat model: any process running as the user can request the credential without re-authenticating.
  • wincred (Windows) stores credentials in the Windows Credential Manager. The Credential Manager is encrypted with the user’s profile keys. The risk is similar to macOS Keychain.
  • manager is Git Credential Manager (GCM), a Microsoft- maintained cross-platform helper. It uses the platform’s secure store (Keychain on macOS, Credential Manager on Windows, Secret Service on Linux) and adds features like multi-factor authentication prompts and Azure DevOps integration.
  • libsecret (Linux) stores credentials in the GNOME Keyring or KDE Wallet via the Secret Service D-Bus API. The keyring is encrypted with the user’s login password. The risk is that the keyring must be unlocked for the helper to read, which on some Linux distributions means the keyring is not unlocked at all for headless sessions.
git config --global credential.helper cache --timeout=3600
git config --global credential.helper osxkeychain
git config --global credential.helper manager
git config --global credential.helper libsecret
git config --global credential.helper store

The first three are workstation-appropriate. The fourth is the Linux headless fallback and often fails silently. The fifth is plaintext and should be treated as a credential leak waiting to happen.

Choosing a helper

The right helper depends on the deployment:

  • Developer workstation (macOS, Windows, modern Linux): use manager (GCM) or the platform-native helper. The credential is encrypted at rest, the user gets prompts for new hosts, and the helper handles MFA correctly.
  • Headless Linux server with a logged-in user: use libsecret if a keyring is configured and unlocked, or cache --timeout=... if the threat model is “the credential is short-lived”. Never use store.
  • CI runner: use short-lived tokens injected by the runner (GITHUB_TOKEN, GITLAB_TOKEN, deployment keys) and a helper like cache that holds them for the duration of the job. Never persist a credential to disk on a shared runner.
  • Production deploy host: use SSH keys with ~/.ssh/config and the SSH agent, not HTTPS credentials at all. SSH keys with a passphrase and an agent are the most operationally simple secure option for machine-to-machine Git access.

The wrong helper is whichever one writes the credential to a file that outlives the credential’s lifetime. For most deployments that means avoiding store and avoiding any helper whose backend is a plaintext file.

Multiple helpers

credential.helper accepts multiple values; Git tries them in order. The pattern is to put the most-secure helper first and fall back to a less-secure one:

git config --global credential.helper manager
git config --global credential.helper cache --timeout=3600

GCM handles the credentials it knows about; anything GCM cannot resolve falls through to cache, which holds the credential for one hour. The fallback is the explicit acknowledgement that no helper covers every case, and that an in-memory fallback is better than an interactive password prompt for the duration of a deploy.

Production discipline

  1. Use a secure-store helper on every workstation. osxkeychain, wincred, manager, or libsecret - never store.
  2. Use short-lived tokens on every CI runner. A token that expires in 60 minutes is a token that does not need to be persisted; the runner configures the helper for the duration of the job and lets the helper forget.
  3. Treat ~/.git-credentials as a credential leak. If a machine has ever run store, the file should be deleted and every credential it ever contained should be considered compromised.
  4. Use SSH keys for machine-to-machine Git. The SSH agent with passphrase-protected keys is the most operationally simple secure option for production deploy hosts and shared runners.
  5. Audit the helper list. A surprising helper on a shared runner is a surprising security posture; git config --list --show-origin | grep credential is the right diagnostic.

Quiz

Knowledge check · 4 questions

  1. Q1. An engineer runs `git config --global credential.helper store` on a workstation. Where does the credential live after the engineer authenticates once?

  2. Q2. Multiple credential helpers can be configured at the same scope; Git tries them in the order they were declared and falls through to the next helper if the current one returns no credential.

  3. Q3. Name the four production-grade credential helpers and the platform or situation each one is the right choice for.

  4. Q4. Diagnose a credential leak on a shared runner that has been using the `store` helper, and recommend a remediation that does not require a runner rebuild.

    A shared CI runner has been using `credential.helper=store` for two years. A backup of the runner's home directory was exfiltrated by a separate incident and contains `~/.git-credentials` with the runner's deploy token for the production remote. The team needs to contain the leak, switch the helper, and prevent recurrence without rebuilding the runner from scratch.

Passing score: 75%. Answers are checked in this browser.