The client credential hygiene checklist
A practical checklist for reviewing a client's secret-handling practices — repos, CI/CD, storage, and what to do the moment a credential turns up exposed. Built for MSPs and vCISOs running security reviews. Rebrand it, print it, or hand it over as-is; every practice on it is a standard, verifiable control, not a marketing claim.
Prefer this automated, per-client, and branded with your logo? That's the GhostCred MSP white-label report — see how it works.
Where secrets actually leak
Before checking anything, know what you're looking for. The overwhelming majority of credential exposures we see fall into a short, predictable list.
Hardcoded API keys, tokens, or passwords committed directly into source files
Cloud provider keys (AWS, GCP, Azure), payment processor keys (Stripe, PayPal), and SaaS API tokens pasted straight into code instead of pulled from config.
`.env` files or config files committed to version control
Especially early in a project, before `.gitignore` is set up, or after someone force-adds a file to unblock a deploy.
Secrets baked into CI/CD pipeline definitions
GitHub Actions, GitLab CI, Jenkinsfiles, and CircleCI configs that reference a raw value instead of a secret-store reference.
Secrets left in git history even after being 'removed'
Deleting a line in a new commit does not remove it from history — anyone with clone access can still find it with `git log -p`.
Credentials embedded in front-end JavaScript bundles
A key that's fine server-side becomes public the moment it ships in a client bundle that anyone's browser downloads.
Shared credentials pasted into Slack, tickets, email, or shared docs
Outside of git entirely, but just as exposed once that channel is searchable by more people than intended.
Repository hygiene
What to check on every client repo, before anything else.
A `.gitignore` exists and actually excludes `.env*`, `*.pem`, `*.key`, and any local config files
GitHub secret scanning and push protection are turned on for every private repo
Free on GitHub for all repos as of the last few years; push protection blocks a commit containing a recognized secret pattern before it ever lands.
A pre-commit secret scanner runs locally before code reaches the repo
Tools like gitleaks, trufflehog, or git-secrets catch a hardcoded key on the developer's machine, before it's pushed anywhere.
Git history has been checked at least once for secrets that predate current hygiene
A one-time gitleaks or trufflehog scan of full history, not just the current branch tip.
No repo is public unless someone deliberately decided it should be
Storage and rotation
Where secrets should live once they're out of the code.
Production secrets live in a dedicated secret manager, not in a shared `.env` file
AWS Secrets Manager, GCP Secret Manager, Azure Key Vault, or HashiCorp Vault — not a flat file synced over Slack or email.
Each environment (dev, staging, prod) has its own credentials
A dev key leaking should never be able to touch production data.
There's a named owner and a documented process for rotating a credential
If nobody knows how to rotate a given key without downtime, that's the moment to find out — not during an incident.
Long-lived static credentials are replaced with short-lived or role-based ones wherever the platform supports it
E.g. AWS IAM roles / STS temporary credentials instead of a permanent access key pair.
Every credential is scoped to the minimum permissions it needs (least privilege)
A key that only needs to read one S3 bucket should not have account-wide access.
CI/CD and automation
Pipelines are a common blind spot — they run with real credentials and are easy to overlook.
Pipeline secrets are stored in the CI/CD platform's encrypted secret store, not in the pipeline YAML itself
Secret values are masked in build logs so a misconfigured `echo` or debug step can't print them in plaintext
Third-party GitHub Actions or CI plugins are pinned to a specific commit or version, not a mutable tag
An unpinned action can be silently changed upstream to exfiltrate whatever secrets it has access to.
Deploy keys and service-account tokens used by automation are reviewed on the same cadence as human access
Access and accountability
Who can see a secret matters as much as where it's stored.
A current list exists of who has access to the secret manager, cloud console, and repo admin settings
Access is removed the same day someone leaves the team or changes roles
Shared logins are eliminated in favor of individual accounts with MFA
There's an audit log for who accessed or changed a secret, and someone actually reviews it periodically
If a secret is found exposed
The response, not the discovery, is what determines whether an exposure becomes an incident. Move in this order.
Rotate the credential immediately — treat 'exposed' and 'compromised' as the same thing
Don't wait to confirm it was actually used. Rotation is cheap; a breach investigation is not.
Revoke the old credential everywhere it was issued, not just in one system
Check access/usage logs for the exposed credential's activity window
Cloud providers (AWS CloudTrail, GCP Audit Logs, etc.) and most SaaS platforms log key usage — check for anything unexpected before and after exposure.
Purge the secret from git history if it was committed, not just from the current file
`git filter-repo` or the BFG Repo-Cleaner, followed by a force-push and a heads-up to every collaborator to re-clone.
Document what happened, when it was found, when it was rotated, and what was checked
This is exactly what an auditor asks for under SOC 2, HIPAA, NYDFS 500, or CMMC — a paper trail beats a verbal 'we handled it.'
Note the root cause and close the gap that let it happen
A missing `.gitignore` entry, no pre-commit hook, an over-scoped key — fix the pattern, not just the one instance.
Want this checklist turned into a scored, branded PDF you can hand a client at the review — with findings mapped to SOC 2, HIPAA, NYDFS, and CMMC?