Guide

Your .env file is exposed. Here’s what to do now.

If your .env, a wp-config.php backup or .git/config can be downloaded, assume the secrets in it are already in someone else’s hands. Bots request /.env on millions of sites a day. Work through these steps in order — the first two take minutes.

  1. Block the file
  2. Rotate every secret in it
  3. Check whether it was downloaded
  4. Move secrets out of the web root
  5. Scan again

1. Block the file now

Stop new downloads first. It is one config change and a reload. These rules cover every .env, backup and dot-folder path DotenvScan checks (.git, .svn, .aws, .DS_Store), and leave /.well-known/ alone so HTTPS certificates keep renewing.

nginx

Inside the server { } block, above any location ~ \.php$ block — nginx uses the first regex location that matches.

# Dotfiles (.env, .git/…), but keep /.well-known/ for certificates
location ~ /\.(?!well-known(?:/|$)) {
    deny all;
}
# Backup and editor copies (.env.bak, wp-config.php.bak, …)
location ~* \.(?:bak|old|orig|save|swp)$ {
    deny all;
}
sudo nginx -t && sudo systemctl reload nginx

Apache

In the virtual host or in .htaccess (Apache 2.4). A virtual-host change needs a reload; .htaccess applies at once.

# Dotfiles (.env, .DS_Store …) and backup/editor copies
<FilesMatch "(^\.|\.(bak|old|orig|save|swp)$)">
    Require all denied
</FilesMatch>
# Dot-folders (.git, .svn, .aws …), but not /.well-known/
RedirectMatch 404 /\.(?!well-known/)[^/]+/
sudo apachectl configtest && sudo systemctl reload apache2   # httpd on RHEL-family systems

Caddy

@secrets path */.env* */.git/* */.svn/* */.aws/* */.DS_Store *.bak *.old *.orig *.save *.swp
respond @secrets 404
sudo systemctl reload caddy

Two of the checks aren’t dotfiles: a phpinfo page should be deleted, and a public laravel.log means the document root is wrong. Then run DotenvScan again: every path should answer 403 or 404.

2. Rotate every secret in the file

Blocking the file doesn’t un-leak it. Change each credential at its source, deploy the new value, then revoke the old one:

If .git/config was exposed, the whole repository can usually be rebuilt from the open .git directory. Treat every secret ever committed, even in old commits, as leaked — the exposed .git guide covers it.

3. Check whether it was downloaded

Your access logs show whether anyone fetched the file. A 200 response means they got it. zgrep reads current and rotated (.gz) logs alike:

sudo zgrep -hE '"GET /[^ "]*(\.env|\.git/|\.bak|\.old|\.save)[^ "]* HTTP/[0-9.]+" 200 ' /var/log/nginx/access.log*

For Apache, use /var/log/apache2/access.log* (or /var/log/httpd/access_log*). DotenvScan’s own requests show the user agent DotenvScan/1.0. Any other hit means the file was taken: finish step 2 first, then look for unfamiliar activity in the services those keys unlock.

4. Move secrets out of the web root

Blocking rules are a safety net. The real fix is that the file never sits in a public directory:

5. Scan again, and check the whole server

Run DotenvScan again to confirm every path now answers 403 or 404. One exposed file usually means others: to find every secret file on a server — all sites, accounts and backup copies — run ServerSecretVault on the server itself.

Scan your site again