Home / Articles / Software
Software

The .env File Is Not a Vault: How to Prevent Credential Leaks in Software Projects

The .env file is indeed practical for storing local configurations, but it is not an automatically secure secret storage. Understand its limitations and develop simple habits to prevent API keys, database passwords, and tokens from being exposed...

File .env Bukan Brankas: Cara Mencegah Kredensial Bocor dari Proyek Software

The .env file is often the first solution when an application needs an API key, database password, or service token. Its format is simple, easy for libraries to read, and convenient for local development. The problem arises when this file is treated like a vault, whereas it is usually just a plain text file on a computer or server.

If the file gets included in a Git repository, printed in logs, read by other processes, or copied to unprotected backups, the secrets within can be exploited by others. Therefore, using a .env file is not a mistake. The danger lies in assuming that the file name alone is sufficient to provide protection.

What does the .env file actually contain?

The .env file typically contains key-value pairs of configuration, for example:

DATABASE_URL=postgres://user:password@localhost/app
PAYMENT_API_KEY=sk_live_example
APP_SECRET=secret-value

In the application, these values are read as environment variables, which are configuration information separated from the program code. This approach helps us use different configurations for the developer's computer, testing server, and production server without changing the source code.

However, environment variables do not automatically mean secrets are encrypted. Under certain conditions, these values can appear in debugging, process dumps, container configurations, or application logs. OWASP also warns that secrets should not be written in source code, repositories, or logs, and there should be mechanisms for access restriction and rotation. The OWASP Secrets Management Guide explains the risks and best practices for managing secrets in more detail.

Common Mistakes

1. Relying solely on .gitignore

Adding .env to .gitignore is a necessary step, but it only prevents untracked files from being added. If the file has been committed previously, removing it from the working folder does not automatically delete it from the repository history.

Example of basic rules:

.env
.env.*
!.env.example

The .env.example file can contain variable names without secret values, so team members understand the required configuration:

DATABASE_URL=
PAYMENT_API_KEY=
APP_SECRET=

Also document that each developer needs to fill in those values in their local .env file, rather than replacing the contents of .env.example with real credentials.

2. Thinking deleting a commit is enough

Once credentials have entered the repository, consider them leaked. Deleting lines in the latest commit does not resolve the issue because older copies may still be stored in Git history, forks, local clones, caches, or backup systems.

A safer sequence is to revoke or replace the credentials first, then clean the repository history if necessary. Cleaning history without revoking tokens remains risky because someone may have already copied them before the file was deleted.

3. Storing secrets in Dockerfile or deployment configurations

Including tokens via ENV or ARG in a Dockerfile can cause them to be stored in the image metadata or visible to anyone with access to that image. OWASP recommends that secrets be provided at deployment or runtime, not embedded when the image is built.

For small projects, use secrets or variables provided by the deployment platform. For larger systems, consider a secret manager that supports access control, auditing, and rotation. Environment variables can still be a practical choice, but do not consider them a single layer of protection.

Checklist Before Pushing

  1. Check the changes to be sent. Run git diff --cached before committing. Don’t just look at file names; also search for patterns like api_key, token, password, and private_key.
  2. Ensure secret files are not being tracked. Use git status. If .env has already entered the index, the .gitignore rule alone is not enough.
  3. Use a secret scanner. Scanners can help find token patterns that may have been missed during manual checks. Scan results still need to be reviewed as they can produce false positives, which are texts that appear to be secrets but are not.
  4. Enable protection before pushing if available. GitHub Push Protection can block detected credentials before they enter the repository. This feature is not a comprehensive guarantee as the detection coverage depends on the types and patterns of secrets supported.
  5. Limit access rights. Use tokens with minimum permissions. Tokens for reading data should not have rights to delete or modify the entire account.

GitHub explains that Push Protection works by scanning changes during the push process and blocking recognized secrets. This feature helps prevent leaks from the start, but it is not an excuse to neglect code reviews or proper credential management. The GitHub Push Protection Documentation also explains detection limitations and bypass processes.

If a secret has leaked

Do not wait for signs of misuse. Treat tokens visible in repositories, issues, screenshots, logs, or public chats as credentials that have been exposed.

  1. Revoke or rotate the token. Create new credentials and disable the old ones.
  2. Check usage activity. Review access logs, billing, configuration changes, and unusual account activity.
  3. Identify the leak path. Investigate whether the source is from commits, logs, CI/CD pipelines, container images, or developer devices.
  4. Clean the source. Remove secrets from the code and, if necessary, clean the repository history. Do not rely on deletion as a substitute for rotation.
  5. Document the fix. The team needs to know when the secret leaked, who responded, and how to prevent similar incidents.

What does this mean for us?

For personal projects, the most important habit is to separate configuration from source code, include .env in .gitignore, and not attach real tokens in tutorials or screenshots. For teams, add secret checks to the pull request workflow and use different credentials for local, staging, and production environments.

In summary, the .env file is a practical way to manage configurations, not a complete security system. Stronger protection comes from a combination of several habits: secrets are not written to repositories, access is kept as narrow as possible, tokens can be revoked, logs do not leak their values, and every leak is treated as if it has been fully exploited.

Sources & Further Reading

– Rio Yotto @rioyotto