critical Exposed: /.env file readable over HTTP
Your deployment serves /.env directly to anyone who asks. The file contains a live database connection string and a payment-processor secret key. There is no login and no exploit involved - a single unauthenticated GET request returns the whole file. Automated scanners hit this path on every site they crawl, so a leaked /.env is typically found within hours of going public.
What this means: Anyone on the internet can read the password to your production database and your live payment key. With the database URL they can connect directly and read or alter customer records, orders, and password hashes. With the payment key they can move money and issue refunds as you. Treat every credential in this file as already compromised.
Found on: https://shop.acme-demo.example/.env
Evidence (redacted):
DATABASE_URL=postgres://app:****@db.shop-acme.internal:5432/shop_prod
STRIPE_SECRET_KEY=sk_live_****REDACTED****
SESSION_SECRET=****REDACTED****
SMTP_PASSWORD=****REDACTED****
Fix: Block dotfiles at the web server so /.env can never be served, then rotate every credential the file contained - assume it has already been copied.
Where: Web server / edge config (Nginx, Apache, or your host's headers/redirects file).
# Nginx: refuse any path that starts with a dot
location ~ /\. {
deny all;
return 404;
}⚠ Rotate the credentials FIRST, then block the file. Blocking access does not un-leak a secret that was already public - a copied database password is still valid until you change it.
high Exposed admin panel at /admin (no auth wall)
The admin login is reachable from the open internet and fingerprints as a known CMS admin console. Credential-stuffing and brute-force tools target this exact path with lists of leaked passwords. An admin panel does not belong on the public web - it should sit behind IP allow-listing, a VPN, or an auth proxy, so that reaching the login form already requires being inside your perimeter.
What this means: An attacker who guesses or reuses one admin password owns your whole site - content, customer data, and the ability to inject a card skimmer into your checkout. Because the panel is public, they can attack it continuously and silently, with no need to be anywhere near your network.
Found on: https://shop.acme-demo.example/admin
Fix: Restrict /admin to known office and VPN IP ranges, or put it behind an authenticating proxy (Cloudflare Access, an SSO gateway) so unauthenticated visitors never reach the login form.
Where: Edge / reverse proxy in front of the app, or the app's host firewall rules.
# Nginx: only let known networks reach the admin panel
location /admin {
allow 203.0.113.0/24; # office
allow 198.51.100.7; # VPN egress
deny all;
}⚠ Confirm the allow-list covers every network your real admins use (remote staff, VPN egress IPs) before you deploy, or you will lock yourself out alongside the attackers.
high Subdomain takeover risk: dangling CNAME on assets.shop.acme-demo.example
This subdomain points (via CNAME) at a cloud bucket host that no longer claims it. The DNS record is live but the target is unowned, so anyone can register that target on the provider and start serving their own content from your subdomain. The browser will show your domain, your padlock, and your name.
What this means: An attacker can stand up a convincing phishing page on a subdomain your customers already trust - assets.shop.acme-demo.example reads as you, not as a stranger. It is also a clean way to steal cookies scoped to your parent domain and to bypass email and link filters that trust your brand.
Found on 2 pages:https://assets.shop.acme-demo.example/
https://assets.shop.acme-demo.example/img/
Fix: Remove the dangling DNS record, or re-claim the resource on the provider it points at. Then audit every CNAME that targets a third-party platform (S3, GitHub Pages, Heroku, Netlify) for unclaimed targets.
Where: Your DNS provider's zone for shop.acme-demo.example.
# Delete the record whose target is no longer claimed:
assets CNAME acme-demo-assets.s3-website.amazonaws.com. ; <- remove
⚠ Confirm the target is genuinely unused before deleting - if a live service still depends on it, pull the dependency first, then remove the record.