Try This Right Now
Open a new tab. Type your domain followed by /.env and hit enter. If a file downloads or text appears on screen, your database credentials, API keys and every secret your application uses are publicly available to anyone on the internet.
In our assessments, 78% of applications built with AI coding tools have this exact problem. It takes about 3 seconds to check and roughly 5 minutes to fix. The rest of this post explains why it happens and what to do about it.
Why .env Files Get Exposed
The .env file is where applications store sensitive configuration: database passwords, API keys, JWT secrets, SMTP credentials. The file sits in the project root directory. AI coding tools put it there because that is where every framework expects it.
The problem is deployment. When you deploy a project built with Cursor or Bolt, the default server configuration typically serves files from the project root. Apache and Nginx do not know the difference between index.html and .env. If the file is in the web root and there is no rule blocking it, the server will serve it to anyone who asks.
AI tools do not add these blocking rules. They generate the .env file, reference it in the application code and move on. The deployment documentation, if it exists at all, does not mention this risk.
What Attackers Actually Do With .env Files
Automated scanners crawl the internet 24/7 looking for exposed .env files. This is not theoretical. It is one of the most common automated attacks on the web. Within hours of deploying a new application, bots will request /.env, /.env.backup, /.env.local and /.env.production.
When they find one, the results cascade fast. Database credentials give direct access to all user data. Stripe or payment keys enable financial fraud. SMTP credentials allow sending phishing emails from your domain. AWS keys give access to your entire cloud infrastructure. JWT secrets allow forging authentication tokens to impersonate any user.
The attacker does not need to be sophisticated. The scanning tools are free, the technique is well documented and the payoff is enormous.
How to Check (Beyond the Browser)
The browser test catches the obvious case. Here is a more thorough check:
# Check the main .env file
curl -s -o /dev/null -w "%{http_code}" https://yourdomain.com/.env
# Check common variants
curl -s -o /dev/null -w "%{http_code}" https://yourdomain.com/.env.local
curl -s -o /dev/null -w "%{http_code}" https://yourdomain.com/.env.production
curl -s -o /dev/null -w "%{http_code}" https://yourdomain.com/.env.backup
curl -s -o /dev/null -w "%{http_code}" https://yourdomain.com/.env.example
A 200 response means the file is accessible. You want 403 (forbidden) or 404 (not found). If you get 200 on any of these, stop reading and fix it now.
Also check if your .env file is committed to your Git repository:
git log --all --full-history -- .env
If that command returns any results, the file is in your Git history. Even if you deleted it later, anyone with access to the repository (or a leaked .git directory) can retrieve it.
Fix 1: Block .env With .htaccess (Apache)
If you are running Apache, add this to your .htaccess file in the web root:
# Block access to dotfiles
<FilesMatch "^\.">
Order allow,deny
Deny from all
</FilesMatch>
This blocks access to all files starting with a dot, which catches .env, .git, .htpasswd and other sensitive dotfiles.
Fix 2: Block .env With Nginx
If you are running Nginx, add this inside your server block:
# Block access to dotfiles
location ~ /\. {
deny all;
return 404;
}
Reload Nginx after making the change:
sudo nginx -t && sudo systemctl reload nginx
Fix 3: Add .env to .gitignore
If you have not already, add .env to your .gitignore:
# Add to .gitignore
.env
.env.*
.env.local
.env.production
If the file was already committed, remove it from tracking without deleting the local file:
git rm --cached .env
git commit -m "Remove .env from tracking"
Important: this removes the file from future commits but does not remove it from history. If your repository is public (or ever was public), assume the credentials in that file are compromised and rotate them.
Fix 4: Move .env Outside the Web Root
The safest approach is to keep the .env file outside the directory your web server serves. If your web root is /var/www/html/, put your .env at /var/www/.env and update your application to read from there:
# Node.js with dotenv
require('dotenv').config({ path: '../.env' });
# Python with python-dotenv
from dotenv import load_dotenv
load_dotenv(dotenv_path='../.env')
Fix 5: Use Platform Environment Variables
Most hosting platforms (Vercel, Railway, Render, Heroku, AWS) have built-in environment variable management. Use it instead of files. Set your variables in the platform dashboard and remove the .env file from your deployment entirely.
This eliminates the risk of file exposure because there is no file to expose.
If Your .env Was Already Exposed
If you found that your .env file was accessible, assume every credential in it has been compromised. Automated scanners likely found it before you did. Here is what to do:
- Block access immediately using the fixes above
- Rotate every credential in the file: database passwords, API keys, JWT secrets, SMTP passwords
- Check your Stripe dashboard for unauthorized charges
- Check your AWS billing for unexpected resource creation
- Review your application logs for unauthorized access
- Check your email service for forwarding rules you did not create
For a more comprehensive assessment of your application's security posture, including checks beyond just .env exposure, see our secure vibe coding setup guide.
The Bigger Picture
Exposed .env files are the canary in the coal mine. If your application has this issue, it almost certainly has others. Missing authorization checks, SQL injection, weak password hashing and unprotected admin routes follow the same pattern: the AI built the feature but not the security around it.
Fix the .env issue today. Then keep going.