CLOUD
development

Secrets and .env Management: Keeping Your Database Keys Out of Git

CLOUD|September 18, 2026|8 min read|126 views
Secrets and .env Management: Keeping Your Database Keys Out of Git

One leaked database key in a public repo can be exploited within minutes. The fix is practical: keep .env out of Git, set file permissions to 600, rotate keys every 90 days, and scrub the history the moment a leak happens.

The most dangerous line in your project is not complex code. It is the .env file holding your database password, payment key, and API tokens. If that file reaches a public GitHub repository, your response window is measured in minutes, not days, because automated scanners inspect new commits the moment they are pushed. The direct answer is five steps you apply today. First, add .env to .gitignore before your first commit. Second, set the file permission on the server to 600 so only the owner can read and write it. Third, keep a .env.example with empty values as a reference for your team. Fourth, rotate every key every 90 days and immediately after any suspicion. Fifth, if a key leaks, deleting it in a new commit is not enough because it stays in history, so you must rotate the key first and then scrub the history itself. These rules protect the one part whose exposure brings everything else down, since a single key can hand an attacker full access to your customer data.

The core idea is total separation of secrets from code. Code goes to Git, secrets live on the server and in the minds of a few team members only. Any mixing of the two is the vulnerability, and most real incidents come from this mixing rather than a sophisticated attack.

Why leaks are faster than you think

When you push a commit containing a key to a public repo, an automated chain begins, not a human one. Tools like TruffleHog, Gitleaks, and private bots watch the public GitHub events API and scan every push for known patterns such as an AWS key starting with AKIA or a Stripe key starting with sk_live. Keys with a fixed prefix are detected with very high accuracy because a single regular expression matches them.

The result is a very narrow danger window. Repeated security research has recorded exposed cloud keys being exploited in under an hour at times, and in known cases within minutes. Even if you delete the file after five minutes, a bot may already hold its copy. That is why the decisive rule stands: any key that touched a public repo is considered burned and must be rotated, not merely hidden.

Why deleting in a new commit is not enough

Git is a history system, not a file system. When you delete .env in a new commit, it disappears from the branch head (HEAD) but remains fully preserved in the earlier commit, and anyone can extract it with git log or git show on that commit. So a leak must be handled from two angles: rotate the key immediately, which makes the leaked copy worthless, then clean the history if needed.

Layer one: prevent access from the start

Prevention is far cheaper than the cure. Order your defense this way:

  • .gitignore first: add .env and all its variants (env.local, env.production.local) to .gitignore in the project's very first commit, before any secrets file exists. This blocks the most common human error.
  • A safe reference file: commit a .env.example with variable names only and empty values, so every new developer knows what is needed without ever seeing a real value.
  • Pre-commit hook: install a tool like Gitleaks as a pre-commit hook so it scans changes locally and rejects any commit with a secret pattern before it even leaves your machine.
  • CI review: run the same scan in your pipeline as a second safety net for anyone who forgot the local hook.

Layer two: file permissions on the server

When .env lands on your server, the risk changes: who can read the file on the system? The default is sometimes 644 (world readable), which means any other process or user on the server can read your secrets. The correct setup:

CommandPermissionMeaning
chmod 600 .envrw-------Owner reads and writes only, nobody else reads
chmod 640 .envrw-r-----Owner writes, the server group reads only
644 (common mistake)rw-r--r--Every system user reads the secrets

On a cloud server where you hold root, set the file to 600 and make its owner the application user (such as www-data or the PHP-FPM user) rather than root, so the app reads it and nobody else does. Also make sure the file sits outside the public web directory so it is never served over HTTP by accident.

Layer three: rotate keys every 90 days

Even without a leak, a key that never changes grows riskier over time: it seeps into logs, backups, and team chats. The practical rule is to rotate every sensitive secret every 90 days at most, and immediately when an employee leaves or on any suspicion. Gateway keys (payment, WhatsApp, SMS) and cloud access keys deserve regular rotation first.

To avoid downtime during rotation, use an overlap window: create the new key, run it alongside the old one for a few hours, update .env and restart the app, then revoke the old key after confirming. Most API providers allow two active keys temporarily for exactly this purpose.

When you need Vault and when you don't

Heavier tools like HashiCorp Vault and AWS Secrets Manager offer automatic rotation, encryption at rest, and a detailed access log for every secret read. But they add another service you run, maintain, and secure, and it becomes its own point of failure if it goes down.

SituationThe right fit
One app on one or two serversA .env file at 600 with regular manual rotation is plenty
Small team, few secrets.env plus a team password manager to share values safely
Dozens of services, frequent rotation, strict auditVault or Secrets Manager earns its cost here
A governance requirement for a per-secret access logA central secrets solution with auditing

The takeaway: do not build enterprise secrets infrastructure for a small project. A permission-controlled .env with real rotation covers the overwhelming majority of cases, and managed cloud hosting is designed to keep your sensitive files outside the public directory by default.

What to do in the first minutes after a leak

If you discover an exposed key, order your response in this decisive sequence:

  • Rotate first, don't clean first: create a new key and revoke the old one immediately. This stops the bleeding even if the leaked copy still exists somewhere.
  • Check access logs: review database, gateway, and server logs for strange activity since the suspected leak, looking for IP addresses or queries you don't recognize.
  • Scrub the history: use git filter-repo (the officially recommended replacement for filter-branch) to remove the file from every commit, then force push and tell the team to re-clone.
  • Document the incident: record what leaked, when, and what you did. This helps auditing and improves your process later.

Secrets in containers and CI pipelines

Modern environments add new places secrets can leak from, and three are the most dangerous. First, environment variables in Docker files: writing a secret directly in the Dockerfile with an ENV instruction bakes it into the image layers, so it stays readable to anyone who pulls the image via docker history, even if you delete it in a later layer. The correct way is to pass secrets at runtime through --env-file or orchestrator secrets, not bake them into the image. Second, CI/CD pipeline logs: printing an environment variable in a build step exposes it in a log that everyone with repo access may see, so make sure your CI tool masks variables marked as secret, and never print the full environment for debugging. Third, backups: a database dump or a disk image can contain the entire .env, so treat backups with the same sensitivity as the original and encrypt them at rest.

One unified rule ties this together: a secret is injected at runtime from a single trusted source, never copied into images, logs, or repos. Every extra copy of a secret is an extra attack surface, so the fewer places it lives, the lower the chance of a leak, and the easier it is to rotate because you know exactly where it lives. This completes the three earlier layers, preventing Git access, setting server permissions, and regular rotation, so secrets stay governed from the first commit to the last backup.

Practical conclusion

Start today with three steps: confirm .env is ignored with git check-ignore .env, set secret file permissions on the server to 600, and set a reminder every 90 days to rotate keys. Install Gitleaks as a pre-commit hook this week, since it prevents the incident before it happens at a cost of minutes. And if you want a server where you hold full root to set permissions and separate secrets properly, review the pricing and plans on Riyadh servers with a response time near 8ms. Secrets are not a detail, they are the foundation on which the security of everything you built stands.

Share