F5/100
Security report for

shop.acme-demo.example

Critical exposure. At least one thing an attacker can use right now.
A
B
C
D
E
F
Only 6% of the sites we've scanned grade F or worse - this is the serious end, not the middle.
1Critical
2High
2Medium
1Low
1Info

shop.acme-demo.example is serving a live secrets file and an open admin panel to the entire internet - no login, no exploit, just a GET request. Both are fixable today; both are exactly what an attacker scans for first. This is an example report; scan your own domain to get yours.


Full report unlocked. All 7 findings below - every path, what it means, and the exact fix. Yours to keep and share.

What an attacker would notice

3
critical

Exposed: /.env file readable over HTTP

SC-02001
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.
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****
Remediation
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)

SC-03010
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.
Evidence:
Remediation
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

SC-09020
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.
Remediation
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.

How an attacker could chain these

attack path
An attacker's five-minute path in
It starts with the /.env file, which hands over a live database password and a payment key for free. The open /admin panel is the next stop - somewhere to try those same credentials, or to drop a card skimmer into the checkout your customers actually use. And the dangling subdomain is a trusted-looking home for the phishing page that harvests the next round of logins. None of these needs an exploit. They're things left sitting in public view, and they chain.
Exposed: /.env file readable over HTTPExposed admin panel at /admin (no auth wall)Subdomain takeover risk: dangling CNAME on assets.shop.acme-demo.example

Lower-urgency hardening. Worth tightening once the items above are closed.
medium

Missing HSTS header

SC-01001
The site doesn't send Strict-Transport-Security, so a visitor's first request can be silently downgraded to plain HTTP by a network attacker before the redirect to HTTPS happens - the window where session cookies and login forms are exposed.
What this means. On hostile networks (cafe wifi, a compromised router) an attacker can intercept that first unencrypted request and read or tamper with it. HSTS tells browsers to always use HTTPS from the very first byte, closing the window.
Remediation
Send Strict-Transport-Security on every HTTPS response, then submit the domain to the HSTS preload list so browsers enforce it even on a first visit.
Where: Web server response headers (or your edge / CDN header rules).
Strict-Transport-Security: max-age=63072000; includeSubDomains; preload
includeSubDomains forces HTTPS on every subdomain - make sure they all serve valid TLS before you add it, or they'll break.
medium

Content-Security-Policy allows 'unsafe-inline'

SC-01005
The CSP permits inline scripts, which defeats much of its value as an XSS mitigation - a single injected <script> runs unimpeded, exactly the case CSP exists to stop.
What this means. If any input on the site is ever reflected without escaping, an attacker's script runs in your visitors' browsers - stealing sessions or injecting a card skimmer at checkout. A strict CSP is the safety net that stops that script from executing at all.
Remediation
Move inline scripts to external files or attach a per-request nonce, then drop 'unsafe-inline' from script-src.
Where: Content-Security-Policy response header.
Content-Security-Policy: script-src 'self' 'nonce-<per-request>'; object-src 'none'; base-uri 'self'
Roll this out with Content-Security-Policy-Report-Only first and watch the violation reports, so you catch any legitimate inline script before it's blocked for real users.
low

Cookies missing Secure / HttpOnly flags

SC-01018
A session cookie is set without HttpOnly (so client-side JavaScript can read it) and without Secure (so it can be sent over plain HTTP).
What this means. Without HttpOnly, any XSS on the site can steal the session cookie outright. Without Secure, the cookie can leak over an unencrypted connection. Both flags are free to add and close two easy session-hijack routes.
Remediation
Set both flags, plus SameSite, on every session cookie.
Where: Wherever the app issues the session cookie (framework session config or Set-Cookie call).
Set-Cookie: session=...; Secure; HttpOnly; SameSite=Lax; Path=/
info

Server technology disclosed in headers

SC-01012
Response headers reveal the exact server and framework versions, giving an attacker a head start on matching known CVEs to your stack.
What this means. This isn't a hole by itself, but it removes the guesswork - an attacker can go straight to exploits for your exact version instead of probing blindly. Stripping it is cheap and buys you nothing but quiet.
Remediation
Strip or generalise the Server and X-Powered-By headers at the edge.
Where: Web server / reverse proxy header config.
# Nginx
server_tokens off;
proxy_hide_header X-Powered-By;
That's every one of the 7 findings we turned up.

Export & share

Download a PDF to send to a client, or add your grade badge to your repo or site.
Add this badgeSurfaceCheckr Security F
[![SurfaceCheckr Security F](https://surfacecheckr.com/r/demo/badge.svg)](https://surfacecheckr.com/r/demo)

The badge stays live: re-scan and it updates itself, and it links back to this report.


Every finding is a deterministic, passive check - we read only what your site already serves to the public, and never send attack traffic. How the scanner works, and what we don't test →

That was someone else's site. What does yours look like?

Paste your domain below. The grade and the issue count are free, and you'll have it in a couple of minutes.

External, read-only scan. We only request public URLs - never log in, never send attack traffic.