Secrets in MacOS Keychain and OS-Level Credential Stores: The Developer Risk Nobody Audits
July 16, 2026
The Credential Store You Configured Once and Forgot
Every developer's laptop is quietly holding credentials that were stored months or years ago. macOS Keychain, Windows Credential Manager, and GNOME Keyring are designed to make authentication seamless—and they do. That seamlessness is exactly the problem. When you don't have to think about a credential to use it, you also don't think about auditing it, rotating it, or removing it when it's no longer valid.
This article is a practical guide for developers, engineering leads, and MSPs who want to understand what actually ends up in OS-level credential stores, how it gets there, and what concrete steps you can take to reduce the risk.
What Gets Stored There (More Than You Expect)
Most developers think of OS credential stores as holding Wi-Fi passwords and maybe some browser logins. In practice, on a working developer machine they accumulate a much richer set of secrets:
- Git credential helpers. Running
git config --global credential.helper osxkeychain(the default on many macOS Git setups) means every username/password or personal access token you have ever typed into a Git prompt gets stored. This includes tokens for GitHub, GitLab, Bitbucket, and any self-hosted instance. - AWS and cloud CLI credentials. Some AWS SSO configurations and third-party tools store short-lived or long-lived tokens in the Keychain rather than
~/.aws/credentials. - Docker credential helpers. The Docker Desktop credential helper on macOS stores registry passwords and tokens in Keychain by default, including credentials for private registries and Docker Hub.
- npm, pip, and package manager auth tokens. Some toolchain wrappers persist registry tokens through OS-level helpers.
- SSH passphrases. macOS stores SSH key passphrases in Keychain so you aren't prompted on every connection. Those passphrases protect the private keys that unlock servers.
- IDE and editor tokens. VS Code extensions that authenticate with GitHub Copilot, Azure, or other services often store their OAuth tokens via the OS secret store API.
How These Credentials Actually Leak
An OS credential store with strong access controls is generally safer than a plaintext .env file—but it is not invulnerable, and it creates several non-obvious risks.
1. Credential helpers silently write to dotfiles that get committed
The most common failure mode is not Keychain itself being breached—it's the configuration being committed. When a developer shares a .gitconfig, a docker config.json, or a tool-specific config file that references the credential helper, other machines that pull that config may inherit helper settings or, worse, the config file itself may contain cached credential data that was never expected to be there.
Check your ~/.docker/config.json. On a machine where the credential helper is set up correctly, it looks like this:
{
"credsStore": "osxkeychain",
"auths": {}
}
On a machine where the helper was not active when you first logged in, it looks like this:
{
"auths": {
"https://index.docker.io/v1/": {
"auth": "dXNlcm5hbWU6cGFzc3dvcmQ="
}
}
}
That auth value is a base64-encoded username:password string—not encrypted, not protected. If this file ever gets committed to a repo (and it does, frequently), the credential is fully exposed.
2. Malicious or compromised npm packages and scripts
A compromised dependency that gains code execution on a developer's machine can enumerate and exfiltrate Keychain entries. macOS Keychain has per-app access control, but many entries are marked as accessible to "any application," particularly older entries created before tighter defaults were introduced. The attacker doesn't need root—they need the same user context your terminal already runs in.
3. Machine transfers and backups
When a developer gets a new laptop and uses macOS Migration Assistant, the entire Keychain migrates with it, including credentials for services, accounts, or companies that the developer may no longer have legitimate access to. Similarly, Time Machine backups contain the Keychain database, meaning an old external drive holds a snapshot of every credential that existed at backup time.
4. Stale credentials that are never rotated
Because OS credential stores are "set and forget," tokens stored there are rarely included in rotation cycles. A GitHub personal access token stored in Keychain two years ago and still working represents months of additional attack surface that your rotation policy never touched.
How to Audit Your OS Credential Store
Before you can act, you need to know what's there. Here are concrete steps for each platform.
macOS Keychain
- Open Keychain Access (Spotlight → "Keychain Access") and search for terms like
github,aws,docker,npm,token, andapi. Note every entry you don't recognize or no longer actively use. - From the terminal, list Git-stored credentials:
git credential-osxkeychain get(interactive) or use thesecurityCLI to search:security find-internet-password -l github.com - Check your Docker config for plaintext credentials:
cat ~/.docker/config.json | python3 -m json.tool. If you see anauthkey with a value underauths, decode it withecho "<value>" | base64 -dto confirm it's a real credential, then rotate it immediately.
Linux (GNOME Keyring / libsecret)
- Install and use
secret-tool:secret-tool search label ""will enumerate stored secrets. - Check Git credential helpers in
~/.gitconfigforcredential.helper=libsecretorcredential.helper=gnome-libsecret. - On headless servers and CI containers, credential helpers often fall back to writing a plaintext
~/.git-credentialsfile. Always check:cat ~/.git-credentials
Windows Credential Manager
- Open Credential Manager from Control Panel → Windows Credentials. Review "Generic Credentials" for any development-related entries.
- Use PowerShell to enumerate:
[System.Net.CredentialCache]::DefaultNetworkCredentialsor thecmdkey /listcommand.
What to Do With What You Find
- Delete stale entries immediately. If a credential is for a service you no longer use, or a company you no longer work for, delete it. There is no good reason for it to persist.
- Rotate any token you can't verify is still private. If a credential was stored years ago and you've since used Migration Assistant, shared a backup drive, or had a dependency supply-chain incident, treat it as potentially compromised and rotate it.
- Enforce credential helper hygiene across your team. Add
~/.docker/config.json,~/.git-credentials, and tool-specific config files that may cache credentials to your organization's.gitignoretemplates and pre-commit hooks. - Audit your repos and CI pipelines too. OS credential stores are one vector; your repositories and CI configuration files are another. The two risks compound: a leaked
.gitconfigpointing at a helper can make the scope of an exposure much larger.
Where This Fits Into SOC 2 and HIPAA
Both SOC 2 (CC6.1, CC6.6) and HIPAA Security Rule §164.312(a)(2)(i) require controls around access credential management, including ensuring that credentials are not retained beyond their necessity and that access is revoked when no longer needed. Auditors increasingly ask about developer endpoint controls, not just server-side secrets management. Stale credentials living indefinitely in developer Keychains—especially credentials to production systems or systems that handle PHI—are a genuine audit finding waiting to happen.
If you're preparing for a SOC 2 audit, your evidence package should include a policy that addresses credential stores on developer endpoints, not just secrets in code and CI/CD.
Extend Your Audit to Repos and .env Files
A thorough credential audit doesn't stop at the Keychain. The same tokens you find sitting in your OS credential store very likely also appear in commit history, dotfiles, and CI configuration. To close the loop, run a free GhostCred scan against your repositories and surface any exposed API keys, tokens, or IAM misconfigurations before an attacker does—typically in under 60 seconds.
Key Takeaways
- OS credential stores accumulate Git tokens, Docker credentials, SSH passphrases, and IDE auth tokens that are rarely audited or rotated.
- The most common leak path is not Keychain being hacked—it's credential helper config files being committed to repos, or
~/.git-credentialsfalling back to plaintext on servers and CI environments. - Audit quarterly: search Keychain for service-related terms, inspect
~/.docker/config.json, and check for a plaintext~/.git-credentialsfile on every developer machine and build agent. - Rotate anything you can't verify, and delete anything you don't need. The cost of rotation is far lower than the cost of a breach.
See what's exposed in your own code.
Run a free scan