TL;DR
Environment files get exposed through misconfigured web servers, accidental git commits, backup files, and debug pages. Test your own sites right now: try accessing yourdomain.com/.env. If you see content, you have a critical security issue.
The uncomfortable reality
I've been doing security assessments for years, and one of the most common findings is exposed environment files. Not in small, amateur projects - in production applications handling real customer data and processing real payments.
The .env file is the skeleton key to your application. It typically contains:
- Database credentials (full access to all your data)
- API keys for third-party services (Stripe, AWS, SendGrid)
- APP_KEY - Laravel's encryption secret
- Mail server credentials
- Redis/cache passwords
- JWT secrets and OAuth tokens
If an attacker gets this file, they don't need to hack anything else. They have the keys to everything.
How .env files get exposed
1. Misconfigured web servers
This is the most common scenario. Your web server should only serve files from the public directory, but misconfigurations can expose the entire project root.
# WRONG - serves from project root
server {
root /var/www/myapp;
index index.php;
}
# CORRECT - serves from public directory
server {
root /var/www/myapp/public;
index index.php;
}
Even with the correct root, some configurations forget to block dotfiles:
# Add this to your nginx config
location ~ /\. {
deny all;
access_log off;
log_not_found off;
}
For Apache, your .htaccess should include:
# Block access to dotfiles
<FilesMatch "^\.">
Order allow,deny
Deny from all
</FilesMatch>
2. Git commits
"I'll just commit this quickly and fix it later." Famous last words.
Once a file is committed to git, it lives in the repository history forever. Even if you remove it in the next commit, anyone with access to the repository can see it in the history.
# Finding .env in git history
git log --all --full-history -- .env
git show <commit-hash>:.env
The fix isn't just removing the file - you need to rotate all credentials and either rewrite git history (if the repo is private) or consider those credentials permanently compromised.
3. Backup files
Editors and deployment scripts often create backup files. I've found these exposed:
.env.backup.env.bak.env.old.env.save.env~(vim backup).env.swp(vim swap file).env.examplewith real values (yes, really)
Your server configuration needs to block all variations, not just the exact filename.
4. Debug pages and error messages
Laravel's debug mode is a goldmine for attackers. When APP_DEBUG=true in production, exception pages display:
- Full environment variable dumps
- Database queries with bound parameters
- File paths and stack traces
- Server configuration details
Critical Rule
Never run APP_DEBUG=true in production. If you need debugging in production, use proper logging and monitoring tools like Sentry, Bugsnag, or Laravel Telescope (with authentication).
5. Source code disclosure
PHP misconfigurations can serve source files as plain text. If PHP isn't processing .php files correctly, attackers can read your configuration files directly:
# Testing for PHP source disclosure
curl -s "https://target.com/config/database.php" | head -20
Detection methods
Test your own sites
Run these checks against your production sites right now:
# Direct .env access
curl -s -o /dev/null -w "%{http_code}" https://yoursite.com/.env
# Common backup variations
for ext in "" ".backup" ".bak" ".old" ".save" ".example" "~"; do
echo -n ".env$ext: "
curl -s -o /dev/null -w "%{http_code}" "https://yoursite.com/.env$ext"
echo
done
# Git exposure
curl -s -o /dev/null -w "%{http_code}" https://yoursite.com/.git/config
Any response code other than 403 or 404 warrants investigation.
Automated scanning
Include environment file checks in your deployment pipeline:
# GitHub Actions example
- name: Security Check - Env Exposure
run: |
response=$(curl -s -o /dev/null -w "%{http_code}" ${{ secrets.PRODUCTION_URL }}/.env)
if [ "$response" != "403" ] && [ "$response" != "404" ]; then
echo "CRITICAL: .env file may be exposed!"
exit 1
fi
Prevention checklist
Server configuration
- Set document root to the
publicdirectory - Block all dotfiles at the server level
- Block common backup file extensions
- Disable directory listing
- Ensure PHP is processing .php files correctly
Git hygiene
- Add
.envto.gitignorebefore your first commit - Use pre-commit hooks to prevent accidental commits
- Audit repository history for exposed secrets
- Use tools like
git-secretsorgitleaks
# Install git-secrets
brew install git-secrets
# Configure for your repo
git secrets --install
git secrets --register-aws
# Scan history for secrets
git secrets --scan-history
Application settings
- Never set
APP_DEBUG=truein production - Use environment-specific .env files (.env.production, .env.staging)
- Consider using secret management services (AWS Secrets Manager, HashiCorp Vault)
- Rotate credentials regularly, especially after any potential exposure
What to do if you're exposed
If you've discovered your .env file is publicly accessible:
- Fix the exposure immediately - Block access at the server level
- Assume compromise - Treat all credentials as leaked
- Rotate everything - Database passwords, API keys, APP_KEY, all of it
- Check access logs - Look for requests to /.env or similar paths
- Audit for damage - Check for unauthorized database access, API usage, etc.
- Implement monitoring - Alert on any future access attempts to sensitive paths
The bigger picture
Environment file exposure is a symptom of a larger problem: security isn't built into the development process. When deployments are rushed, when configuration is treated as an afterthought, when security reviews happen (if at all) at the end of a project - this is what happens.
The fix isn't just blocking /.env. It's building security into your workflow from day one. Automated checks. Secure defaults. Regular audits. A culture where "it works" isn't good enough - it needs to work securely.
Need a security assessment for your PHP application? I can help identify vulnerabilities before attackers do. Let's talk.