A secret is any credential or key that grants access: an API token, database password, signing key, or private certificate. Keep it out of source code and version history, including “temporary” commits. For a small project, a few clear boundaries—local environment files, restricted deployment settings, and a rotation plan—prevent many common leaks without requiring a large security platform.
Know what counts as a secret
Treat a value as secret if someone could use it to access data, spend money, act as your service, or bypass a control. Examples include cloud access keys, database credentials, payment-provider secret keys, signing keys, session secrets, and private SSH keys.
A public identifier is not automatically a secret. A client-side analytics ID may be designed to appear in a webpage, while the matching admin token must stay private. Read the provider’s documentation and permissions model. Do not rely on variable names like PUBLIC_API_KEY as proof that exposure is safe.
Some values are sensitive even when they do not grant access by themselves: customer data, internal endpoints, recovery codes, and private project details. Handle them according to your data policy rather than labeling everything “just config.”
Keep local development values outside tracked files
A common arrangement uses an ignored local file such as .env.local for development values and a committed .env.example containing only variable names and safe placeholders. Confirm the ignore rule is in effect before adding the file, and check git status before every commit.
Example:
# .env.example — safe placeholders only
PAYMENTS_SECRET_KEY=replace-with-a-local-test-key
DATABASE_URL=replace-with-your-development-database
Do not put a real key in the example file, a README, a screenshot, an issue, or an AI prompt. Use a test credential with restricted scope if the provider offers one. Keep production values separate from local development values.
An ignore rule helps prevent future accidental adds; it does not remove a file already tracked by Git. If a secret has entered repository history, assume it may be exposed even if you delete the latest copy. Rotate or revoke it first, then remove the value from history using the repository host’s documented procedure if needed. Coordinate history rewrites with collaborators because they affect existing clones.
Configure CI and deployment settings carefully
Store deployment credentials in the CI provider’s protected secret settings, scoped to the project and environment that need them. Give preview builds test credentials rather than production credentials whenever possible. Restrict who can edit workflows that have access to secrets; a malicious or compromised workflow can print or transmit them.
Review where environment variables are visible. A frontend build tool may inline variables with a public prefix into browser code. Never place a server credential in a value that is intentionally shipped to the client. If a browser needs an operation requiring a secret, route it through an authenticated server component with authorization and rate limits, rather than exposing the credential.
Rotate secrets when access changes: a teammate leaves, a contractor’s work ends, a key is copied into the wrong environment, or a device is lost. Use separate credentials by service and environment so you can revoke one without taking down unrelated systems.
Prevent and detect accidental commits
Before committing, inspect the staged diff, not just the file list. Search for patterns such as sk_live_, password=, BEGIN PRIVATE KEY, and provider-specific token prefixes. Scanning tools can catch known formats, but they can miss custom tokens and false-positive on examples. Treat scanning as a backstop, not permission to stop reviewing.
Useful safeguards include:
- Ignore local environment files and private key files.
- Require secret scanning or pre-commit checks where available.
- Avoid copying production data into local development fixtures.
- Use separate test and production credentials.
- Limit permissions and expiry for tokens where supported.
- Keep repository write access limited to people who need it.
- Review CI logs and artifacts for accidental output.
Never log a credential to “debug” a request. Log a safe status, a request identifier, or a short non-reversible fingerprint when appropriate. Even partial values can aid correlation or reconstruction depending on the secret format.
If a secret is exposed, act in this order
- Revoke or rotate the credential. Removing it from a file does not invalidate the exposed value.
- Check its scope and activity. Review provider audit logs, usage, billing, and access records for suspicious actions.
- Replace it in the right environments. Confirm local, staging, production, scheduled tasks, and CI all use the new credential.
- Remove the exposed copy from current files and history as required. Follow the provider and repository host’s guidance; do not delay revocation while planning a clean history rewrite.
- Review the exposure path. Was the value in a public repository, build log, shared prompt, issue, or browser bundle?
- Add a guard that would have caught this path. For example, change ignore rules, permissions, scanning, or deployment scopes.
If the value is tied to regulated data, customer accounts, or a contractual reporting duty, follow the organization’s incident response policy and get qualified help. Do not assume that a private repository makes an exposed key harmless.
Use generators appropriately
A random generator can create a strong secret value, but it does not store or rotate it safely. Use the credential manager provided by the service or your organization where possible. For an application secret, follow the framework’s guidance on generation, storage, and rotation; do not reuse a human login password.
A password generator can help demonstrate random string generation, but check its handling model before using it for a production credential. Do not paste a generated secret into a public ticket or web checker. Record who owns the credential and how it will be rotated without recording the secret itself.
Separate secret types and environments
Not all credentials have the same scope. A read-only development key, a production database password, and a signing key should not share one storage location or access policy. Label secrets by service, environment, and owner in the secret manager, while avoiding the secret itself in tickets or documentation.
Use separate credentials for local development, automated tests, staging, and production where the provider supports them. This makes it possible to revoke a test credential without interrupting production and reduces the damage if a developer machine is compromised. If a provider offers short-lived credentials or workload identity, evaluate that option instead of keeping a long-lived key in CI.
In a monorepo, scope each workflow to the packages and environments it needs. A build job for a public documentation page should not receive access to a production database key. Review third-party actions and build scripts that run in a secret-bearing workflow; code with permission to run there may be able to read or exfiltrate those values.
Make onboarding and offboarding explicit
Document who can create, approve, rotate, and revoke each production credential. When a teammate joins, grant the smallest required access. When someone changes roles or leaves, remove access and rotate shared credentials according to policy. Removing an account from the repository does not necessarily revoke cloud keys or tokens they could previously copy.
For contractors and service providers, use credentials with a defined owner and end date. Review access after a project completes. Avoid a single “team key” that stays active indefinitely because nobody knows which integration uses it.
Watch logs, artifacts, and support channels
Secrets can leak outside source files. Check CI output, deployment logs, crash reports, browser bundles, build artifacts, support tickets, screen recordings, and chat transcripts. Turn off verbose request logging around authorization headers and redact sensitive query parameters. If a provider returns a token once, store it through the approved secret mechanism rather than copying it into a shared note.
When using an AI assistant, treat prompts and attached files as another data-sharing boundary. Do not include production keys or private customer records unless the organization has approved that service and configuration. Replace sensitive values with representative placeholders that preserve the structure needed for debugging.
A secret-scanning alert should be triaged promptly. Confirm whether the value is live, revoke it if exposure is plausible, and then investigate how it entered the channel. Do not paste the full credential into a public issue while asking whether it is secret.
Handle third-party integrations and local tools
A secret can leak through more than a commit. A package script might print environment variables; a crash reporter can attach process context; a local development server may expose debugging data to the network. Review scripts that run in CI and on developer machines, especially before granting them access to production credentials.
Use a safe test key when trying a new integration. Confirm the provider’s dashboard shows the intended scope, expiration, and environment. If the provider supports IP restrictions, resource restrictions, or audience-bound tokens, use them where they fit. A “test” label in a variable name does not reduce the permissions of a live key.
When using a browser-based generator or password utility, do not assume its output is private without checking its processing model. Generating a key locally is only one step; you still need a secure path to transfer it into the deployment secret store. Avoid copying a real credential through clipboard sync, remote desktop, or support chat unless those channels are approved.
Build a rotation that does not cause an outage
Before a scheduled rotation, identify every place the secret is consumed: services, scheduled jobs, CI, local scripts, and rollback procedures. If the provider allows overlapping credentials, create the replacement, deploy it, confirm traffic succeeds, then revoke the old value. If only one active key is permitted, plan a maintenance window or fallback path.
After rotation, search logs and configuration repositories for the old value’s identifier or a safe fingerprint. Do not print the full secret while searching. Keep a record of the rotation date and owner, not the secret itself. This helps answer whether an old deployment or backup still depends on it.
FAQs
Is a private Git repository safe for secrets?
A private repository still has collaborators, integrations, backups, logs, and possible access mistakes. Keep credentials out of version history and use protected secret storage for values that grant access.
Is .gitignore enough?
It prevents some untracked files from being added, but it does not hide files already committed, nor does it protect secrets embedded in other tracked files. Review the staged diff and rotate any exposed credential.
Can I put an API key in frontend environment variables?
Only if the provider explicitly designed that key for public client use and its permissions are appropriately limited. Build systems often embed public-prefixed values in browser code, where anyone can inspect them.
Should I delete a leaked key from Git history?
Revoke or rotate it first. Then follow your Git host’s procedures for removing sensitive history and coordinate the rewrite with collaborators. Deleting the current file alone leaves old commits intact.
Next step
Check the repository’s ignored files, staged diff, deployment secret settings, and client bundle boundaries today. If a real credential has already been committed, revoke it before attempting cleanup.
