.env Files Are Not Secrets: How Secrets Leak Through GitHub, AI Agents, CI/CD and React

Environment files are everywhere in modern application development.
Developers use .env files to store database credentials, API keys, JWT secrets, cloud credentials, third-party tokens, and other configuration values.
But there is a dangerous misconception:
Putting a secret inside
.envdoes not make the secret secure.
An .env file is usually just a plain-text file.
If an attacker, accidentally exposed repository, CI/CD pipeline, AI coding agent, compromised development machine, or client-side application can access those values, the secrets may be exposed.
This article explains how .env secrets leak, what happens when they are pushed to GitHub, what AI agents have to do with it, and why putting secrets in React or other client-side applications can be especially dangerous.
What Is an .env File?
An .env file is commonly used to store environment-specific configuration.
For example:
DATABASE_URL=postgresql://app_user:[email protected]/app
JWT_SECRET=your-secret-key
STRIPE_SECRET_KEY=sk_live_xxxxxxxxx
AWS_ACCESS_KEY_ID=xxxxxxxx
AWS_SECRET_ACCESS_KEY=xxxxxxxx
This keeps configuration values outside the application's source code.
A typical application may load them like this:
const databaseUrl = process.env.DATABASE_URL;
The important point is:
.envis a configuration mechanism, not a security mechanism.
The file itself does not encrypt the values.
Why .env Files Can Be Critical
An .env file can contain credentials that provide access to important systems.
Depending on the application, leaked environment variables could expose:
- Databases
- Cloud infrastructure
- Payment services
- Email services
- Authentication systems
- Internal APIs
- Storage buckets
- Third-party services
- Encryption or signing keys
The impact depends on what the exposed credential can access.
For example:
DATABASE_PASSWORD=MyPassword123
may look like one leaked password. But if that database account has administrator privileges, the impact could be much larger.
Similarly:
AWS_SECRET_ACCESS_KEY=...
could potentially provide access to cloud resources depending on the permissions attached to that identity.
The real question is not:
"Was the .env file leaked?"
The better question is:
"What permissions did the leaked secrets have?"
What Happens When .env Is Accidentally Pushed to GitHub?
This is one of the most common mistakes.
A developer creates .env and then runs:
git add .
git commit -m "initial commit"
git push
If .env wasn't excluded, the credentials may now be inside the Git repository.
A developer might then add .gitignore rules:
.env
.env.*
!.env.example
This is good practice, but there is an important limitation:
.gitignoredoes not remove secrets that have already been committed.
The secret may still exist in Git history.
Why Deleting .env From GitHub Is Not Enough
Suppose you notice the mistake and delete .env. It is tempting to think the problem is solved. It isn't.
Git repositories maintain history. The secret may still exist in:
- Previous commits
- Branches and tags
- Forks
- Local repositories
- CI/CD caches
- Build artifacts and logs
- Backups
There is another important issue: the secret may have already been copied before you deleted it.
Therefore:
Treat an exposed credential as compromised. Do not rely on simply deleting the file.
What Should You Do If .env Was Pushed?
The first priority should be credential rotation, not file deletion.
A practical incident-response sequence:
- Identify the exposed secrets
- Revoke or rotate them immediately
- Check whether the credentials were used
- Review access logs
- Remove the secrets from Git history
- Add appropriate
.gitignorerules - Replace exposed values with new credentials
- Review who and what had access to the repository
For example, if this was accidentally committed:
STRIPE_SECRET_KEY=sk_live_old_secret
Deleting .env is not the main fix. The first priority should be to revoke or rotate the exposed Stripe credential.
The same principle applies to database passwords, cloud credentials, API tokens, SSH keys, JWT signing secrets, and encryption keys.
Secret rotation is more important than file deletion.
The AI-Agent Problem: A New and Underappreciated Risk
This is the part most security guides skip entirely.
Modern development workflows increasingly involve AI coding agents. An agent may be given access to source code, Git repositories, terminals, build systems, local files, package managers, development environments, and CI/CD systems.
This creates a critical security question:
Does the AI agent really need access to
.env?
If an agent is asked to fix a React component, it probably does not need:
PRODUCTION_DATABASE_PASSWORD=...
AWS_PRODUCTION_SECRET=...
PAYMENT_PROVIDER_SECRET=...
The Blast Radius Problem
When you give an AI agent broad filesystem or repository access, you are not just giving it access to code. You may be giving it access to every secret in your project.
Consider what a typical agent session might access:
Developer
|
v
AI Agent
|
+---- Source code ✅ Needed
|
+---- Test configuration ✅ Needed
|
+---- .env (dev) ⚠️ Usually not needed
|
+---- .env.production ❌ Definitely not needed
|
+---- AWS credentials ❌ Definitely not needed
|
+---- SSH keys ❌ Definitely not needed
Follow the Principle of Least Privilege — For Agents Too
The same security principle that applies to human users, service accounts, and applications applies equally to AI agents:
Give an agent only the access required to complete the task.
Practical steps:
- Use separate
.envfiles for development and production, and ensure agents only have access to development values - Scope your agent's workspace to the directories it actually needs
- Never store production credentials in local files that agents can read
- Treat agent access as you would a junior contractor: task-scoped, not all-access
- Audit what files your agent tool can read before granting it repository access
This is not a theoretical concern. As AI agents become more capable and more deeply integrated into developer tooling, they will increasingly be the path of least resistance for an attacker — or for accidental exposure.
The Biggest React Mistake: Putting Secrets in Client-Side Variables
This is where .env security becomes especially important.
A developer may think:
"The credentials are in
.env, so users cannot see them."
That assumption is dangerous when it comes to client-side applications.
A client-side application runs on the user's device. If a value is included in the browser bundle or intentionally exposed to the client, the user can potentially inspect it.
The browser is not a trusted environment.
React Applications Cannot Keep Browser-Side Secrets
This architecture is dangerous:
React Application
|
v
Database
^
|
DB password exposed to browser ❌
A safer architecture is:
React Application
|
v
Backend API
|
v
Database ✅
The database credentials stay on the server. The browser only receives the data it is authorised to receive.
What About NEXT_PUBLIC_ Variables?
Next.js provides a common example of this problem.
A variable such as:
NEXT_PUBLIC_API_URL=https://api.example.com
is intended to be exposed to client-side code. That is fine for values that are genuinely public.
But this would be dangerous:
NEXT_PUBLIC_DB_PASSWORD=SuperSecretPassword ❌
NEXT_PUBLIC_STRIPE_SECRET_KEY=sk_live_xxxxx ❌
NEXT_PUBLIC_AWS_SECRET_ACCESS_KEY=xxxxxxxx ❌
The NEXT_PUBLIC_ prefix is effectively telling the framework: this value can be exposed to the browser. Never use a public/client-side environment variable for a secret.
"But It Is Inside JavaScript"
Another misconception: "The user can't see my environment variables because they are compiled into the application."
Client-side JavaScript is not a secret storage mechanism. Users can inspect applications through browser developer tools, JavaScript bundles, network requests, source maps, and browser storage.
Anything delivered to the browser should be considered public.
Server-Side vs Client-Side: A Simple Classification
| Variable | Safe to expose? |
|---|---|
NEXT_PUBLIC_API_URL=https://api.example.com |
✅ Yes — genuinely public |
NEXT_PUBLIC_APP_NAME=My Application |
✅ Yes — genuinely public |
DATABASE_URL=... |
❌ No — server-side only |
JWT_SECRET=... |
❌ No — server-side only |
AWS_SECRET_ACCESS_KEY=... |
❌ No — server-side only |
STRIPE_SECRET_KEY=... |
❌ No — server-side only |
ENCRYPTION_KEY=... |
❌ No — server-side only |
Use .env.example
A useful development practice is to commit a template instead of the real .env.
# .env.example
DATABASE_URL=
JWT_SECRET=
STRIPE_SECRET_KEY=
Keep the real file local and add it to .gitignore:
.env
.env.*
!.env.example
This gives developers a clear understanding of which variables are required without exposing the actual credentials.
.env Is Fine for Development — But Production Needs More
Using .env locally is common and often practical. For production environments, consider dedicated secret-management mechanisms such as:
- Cloud secret managers (AWS Secrets Manager, GCP Secret Manager, Azure Key Vault)
- CI/CD secret stores (GitHub Actions Secrets, GitLab CI Variables)
- Container/orchestration secrets (Kubernetes Secrets)
- Enterprise secret-management platforms (HashiCorp Vault, Doppler)
The goal is to avoid distributing production secrets unnecessarily.
CI/CD Can Also Leak Environment Variables
Even if .env never reaches GitHub, secrets can still leak through CI/CD.
Be careful with commands that print environment variables:
printenv
# or
echo $DATABASE_URL
Secrets can accidentally appear in build logs, debug output, error messages, test reports, and build artifacts.
A secret should never be printed simply to verify that it exists.
Common .env Security Mistakes
| Mistake | Why It Matters |
|---|---|
Committing .env |
Pushes secrets into version-controlled, potentially public history |
Assuming .gitignore protects already-tracked files |
Does not remove previously committed secrets |
| Only deleting the leaked file | Credentials may already be compromised |
| Putting secrets in React client-side code | Browser environment is public; secrets are visible |
Using NEXT_PUBLIC_ for secrets |
Client-side variables are intentionally exposed |
| Giving AI agents unnecessary access | Agents can read everything in their workspace scope |
| Using production credentials locally | Dev environment breaches can escalate to production |
| Printing secrets in CI/CD logs | Logs are another form of secret exposure |
A Better Secret Architecture
A safer modern architecture:
┌─────────────────┐
│ Browser │
│ React / Next │
└────────┬────────┘
│
│ HTTPS
v
┌─────────────────┐
│ Backend API │
└────────┬────────┘
│
Secret access
│
v
┌─────────────────┐
│ Secret Manager │
└────────┬────────┘
│
v
┌─────────────────┐
│ Database │
└─────────────────┘
The browser doesn't need the database password. The backend retrieves the required secret from a controlled environment.
What If the Secret Was Already Exposed? — Incident Checklist
- Identify exactly which secrets were exposed
- Immediately revoke or rotate the affected credentials
- Check access logs for suspicious activity
- Determine whether production resources were accessible
- Remove secrets from Git history
- Search branches and tags for copies
- Check CI/CD logs and artifacts
- Check forks and other repository copies where applicable
- Add
.envrules to.gitignore - Create a safe
.env.example - Move production secrets to appropriate secret management
- Review repository and agent permissions
- Document the incident
How Critical Is an .env Leak?
There is no single severity rating for every .env leak. It depends on the secret and its permissions.
| Exposed Value | Potential Impact |
|---|---|
| Public API URL | Usually Low |
| Public application name | Usually Informational |
| Database read-only credential | Medium to High |
| Database admin credential | Critical |
| Cloud credential with broad permissions | Critical |
| Payment provider secret | High to Critical |
| JWT signing secret | High |
| Encryption key | Critical |
| Production admin API token | Critical |
The filename .env does not determine severity. The permissions behind the exposed values determine the real risk.
Final .env Security Checklist
Before deploying an application, ask:
- Is
.envexcluded from Git? - Is
.env.exampleprovided instead? - Are production secrets stored in a dedicated secret manager?
- Are database credentials kept server-side only?
- Are client-side variables free of secrets?
- Are
NEXT_PUBLIC_variables genuinely public? - Are AI agents scoped to only the access they actually need?
- Are CI/CD secrets protected from logs?
- Are credentials scoped using least privilege?
- Is there a process for rotating leaked credentials?
- Are repositories scanned for accidentally committed secrets?
Conclusion
An .env file may look like a small configuration file, but it can contain the keys to an entire application.
A single accidental GitHub commit can expose database credentials, cloud access, payment credentials, authentication secrets, or internal API tokens.
The risk becomes even greater when the same secrets are accessible to AI agents, CI/CD systems, or client-side applications.
The safest mindset is simple:
Don't ask whether your
.envfile is hidden. Ask who — or what — can access the secrets inside it.
Security is not about hiding a file. Security is about controlling access to the secrets.
Secure Your Applications With VAPT Insights
Secret exposure is only one part of application security.
VAPT Insights helps organisations identify security weaknesses across their applications and infrastructure through automated security assessments.
From security headers and SSL/TLS configuration to exposed services and application security checks, continuous visibility helps teams identify problems before attackers do.
Build securely. Scan continuously. Protect what matters.


