A passive external scan. Every finding carries the raw observation the scanner
made and a command you can run yourself to reproduce it - nothing here is written by a model.
14 check groups:
Resolving DNS and checking CAA · Checking SPF and DMARC · Inspecting the TLS certificate and protocol versions · Testing HTTP → HTTPS redirection · Reading security response headers · Checking cookie attributes · Probing the CORS policy · Looking for version banners · Checking allowed HTTP methods · Scanning the homepage for mixed content and insecure forms · Probing for exposed configuration and version-control files · Checking for directory listings · Reading robots.txt and security.txt · Checking for exposed service ports
Starting…
0%
About Website Security Scan
Plenty of scanners hand you a letter grade and a list of scary words. This one gives a grade too, but every point it takes off is tied to a finding that shows the response it actually got and the one-line command that gets you the same response, so a finding is something you can confirm rather than something you have to believe.
What it does
Checks DNS and CAA, SPF and DMARC, the TLS certificate and TLS 1.0/1.1, HTTPS redirection, security headers, cookie flags, CORS, version banners, HTTP methods, mixed content, 23 sensitive paths, directory listings, robots.txt, security.txt and 12 service ports.
Every finding carries the raw observation and a shell command to reproduce it.
Checks that could not run are reported as "not checked" - never quietly as a pass.
Reports download as Markdown or JSON.
How it works
1Enter a domain you are responsible for.
2The scan runs passive probes - ordinary requests, no exploitation.
3Read the findings, each with its evidence, and verify the ones that matter.
No finding is invented
The scanner contains no language model. Severities, impact and remediation are fixed per check, and each finding is generated from a real observation. The on-screen report and the Markdown and JSON downloads are built from the same findings, with no model involved anywhere.
How the grade is worked out
The score starts at 100 and loses 34 points per critical finding, 13 per high, 5 per medium and 1.5 per low, with each severity's total capped (high at 45, medium at 22, low at 9). Informational and passing results cost nothing. 90 and above is an A, 75 a B, 60 a C, 40 a D, anything lower an F. One exposed .env file or reachable database port takes a clean site from 100 to 66, a C; two such findings give 32, an F.
Avoiding false alarms
Before probing paths such as /.git/HEAD or /backup.sql, the scanner requests a random address that cannot exist and records how the site answers. A path is reported as exposed only when it returns HTTP 200, differs from that not-found baseline and matches the file's own signature, so a site that answers every URL with its homepage does not light up with a page of critical findings.
A clean report is not a certificate
These are passive checks against a running site. They do not cover application logic, authentication, access control, or anything behind a login - the places real breaches usually start. Checks that could not complete are listed as not checked for exactly this reason: a pass derived from a failed connection is a false reassurance, and a scan with no findings means nothing was found, not that nothing is there.
Only scan what is yours
Scan domains you own or have written permission to test. The tool refuses hosts that resolve to private or internal addresses, and is rate limited per IP, but the authorisation is still your responsibility.
Questions
Is this an active attack?
No. It makes ordinary GET, HEAD and OPTIONS requests, TLS handshakes (including TLS 1.0 and 1.1 attempts), DNS lookups over Cloudflare DNS-over-HTTPS and plain TCP connects to 12 ports. Nothing is exploited, no form is submitted and nothing is modified.
Can I scan any website?
Only ones you own or are authorised to test. Scanning third-party infrastructure without permission can be unlawful where you are.
Why does a check say "not checked"?
Because it could not be completed - usually nothing answered on that origin. It is reported honestly rather than recorded as a pass.
Can I export the report?
Yes, as Markdown or JSON, for one hour: the report is kept in the server cache for that hour so the downloads work, then expires. Neither export involves a model. The usage record holds the number of findings and the grade, not the domain.
Which files and ports does it test?
Files: 23 fixed paths, among them /.git/HEAD, /.git/config, /.env, /.env.local, /.env.production, /.aws/credentials, /id_rsa, /backup.zip, /backup.sql, /dump.sql, /wp-config.php.bak, /phpinfo.php, /server-status, /actuator/env, each reported only when the response matches that file's own signature; /.well-known/security.txt counts in your favour when it is published. Ports: a plain TCP connection, never a login attempt, to 21 FTP, 23 Telnet, 25 SMTP, 3306 MySQL, 5432 PostgreSQL, 6379 Redis, 27017 MongoDB, 9200 Elasticsearch, 3389 RDP, 5900 VNC, 11211 Memcached, 8080. A reachable database port (MySQL, PostgreSQL, Redis, MongoDB, Elasticsearch) or Telnet is rated critical.
What do the SPF and DMARC checks flag?
Both records are read from public DNS, even for a site that sends no mail, because without them anyone can send mail that claims to be from your domain. No SPF record is medium; an SPF record containing +all, which authorises every server on the internet, is high. No DMARC record under _dmarc is medium; p=none (or no p= tag) only monitors and is low; p=quarantine or p=reject passes. A domain that sends no mail at all can publish v=spf1 -all.
Which security headers does it check, and what value passes?
Six headers on your homepage response. Missing, HSTS and Content-Security-Policy are high, X-Content-Type-Options and X-Frame-Options medium, Referrer-Policy and Permissions-Policy low. Strict-Transport-Security needs a max-age of at least 15552000 (180 days): shorter is low, max-age=0 is medium. Content-Security-Policy is marked weakened (medium) if script-src allows 'unsafe-inline', the policy allows 'unsafe-eval', or default-src or script-src has a bare * wildcard. X-Content-Type-Options must be exactly nosniff. X-Frame-Options should be DENY or SAMEORIGIN, and is not needed when the CSP sets frame-ancestors. Referrer-Policy is flagged only for unsafe-url or no-referrer-when-downgrade. Permissions-Policy only has to be present. Each missing or weak header comes with a curl -sI command so you can check it yourself.
How does it check cookie flags (Secure, HttpOnly, SameSite)?
It reads every Set-Cookie header on your homepage response (up to 12 cookies) and checks each one for Secure, HttpOnly and SameSite. A missing Secure or HttpOnly flag is medium; a missing SameSite attribute on its own is low, and SameSite=None without Secure is called out because browsers reject that cookie. A cookie with all three passes. The usual fix is Secure; HttpOnly; SameSite=Lax (in Django: SESSION_COOKIE_SECURE, SESSION_COOKIE_HTTPONLY and SESSION_COOKIE_SAMESITE). The scan is not signed in, so cookies set only after login are not seen. Check it yourself with curl -sI https://your-site/ | grep -i set-cookie
How does the CORS check work, and when is it critical?
It sends one GET request to your homepage with Origin: https://scanner-probe.example and reads Access-Control-Allow-Origin and Access-Control-Allow-Credentials in the reply. No Access-Control-Allow-Origin header, or a fixed origin that does not echo the probe, passes. Echoing the probe origin together with Access-Control-Allow-Credentials: true is critical, because any site a signed-in user visits could read their responses. Echoing the origin without credentials is medium. A wildcard * is low, or medium if credentials are also allowed (browsers refuse that combination). Only the homepage is probed and no OPTIONS preflight is sent, so test API routes separately with curl -sI -H "Origin: https://scanner-probe.example" https://your-site/api/ | grep -i access-control
What does the TLS check test (certificate expiry, TLS 1.0 and 1.1)?
It connects to port 443 and validates the certificate chain and hostname. A certificate that does not validate is high, an expired one is also flagged critical, and one with fewer than 15 days left is medium; otherwise the subject, issuer, expiry date and SAN names are shown as a pass. The negotiated protocol must be TLS 1.2 or TLS 1.3, anything older is high. It then tries a TLS 1.0 and a TLS 1.1 handshake on their own: a server that accepts either gets a medium finding, because both are deprecated by RFC 8996. If the scanner's own OpenSSL cannot offer the old version, nothing is reported rather than a guess. The nginx fix is ssl_protocols TLSv1.2 TLSv1.3; Check the dates yourself with echo | openssl s_client -connect your-site:443 -servername your-site 2>/dev/null | openssl x509 -noout -dates
Does it check that HTTP redirects to HTTPS?
Yes. It requests http://your-site/ without following redirects. A 301 or 308 to an https:// address passes. A 302, 303 or 307 to HTTPS is low, because browsers do not remember a temporary redirect, so each new visit starts with one unencrypted request. A page served over plain HTTP (a 2xx answer) is high. If port 80 does not answer at all, that is informational, not a failure. The nginx fix is server { listen 80; return 301 https://$host$request_uri; }, then add Strict-Transport-Security. Check it yourself with curl -I http://your-site/
Which HTTP methods does it flag (TRACE, PUT, DELETE)?
It sends one OPTIONS request to your homepage and reads the Allow header, or Access-Control-Allow-Methods when Allow is missing. TRACE, TRACK, PUT or DELETE advertised is medium; PATCH or CONNECT on their own are low; only standard read methods is a pass. If the server sends neither header, nothing is reported. Advertising a method does not prove it works, so confirm it before changing anything. TRACE can echo request headers, cookies included, back to the caller (Cross-Site Tracing). nginx refuses TRACE by default; on Apache set TraceEnable Off. Keep PUT and DELETE to the API routes that need them, behind authentication. Check it yourself with curl -X OPTIONS -i https://your-site/
How does it detect directory listing ("Index of /")?
It requests 7 paths: /, /static/, /assets/, /uploads/, /images/, /files/ and /backup/. A path that answers HTTP 200 with a page whose title or main heading begins "Index of /" is reported as medium (CWE-548), because the listing shows files that are not linked anywhere, such as backups, exports and old versions. If none does, the check passes; if the site cannot be reached, it is reported as not performed. The fix on nginx is autoindex off; (the default, so look for an explicit autoindex on), on Apache Options -Indexes, then move anything sensitive out of the web root. Check it yourself with curl -s https://your-site/uploads/ | head -20
Does it find mixed content and forms that submit over HTTP?
Yes, on the homepage. It reads the HTML as served (no JavaScript is run) and lists every script, link, iframe or img tag whose src or href starts with http://. If any of them is a .js or .css file the finding is medium, because a script or stylesheet replaced in transit runs inside your HTTPS page; images and frames alone are low; none at all is a pass (CWE-311). A form whose action starts with http:// is reported as high (CWE-319), because whatever is typed into it, passwords included, is sent unencrypted. The fix is to change those URLs to https:// or make them relative, and add the header Content-Security-Policy: upgrade-insecure-requests as a safety net. Check it yourself with curl -s https://your-site/ | grep -Eo "(src|href|action)=.http://[^ >]*"
What does it check in robots.txt and security.txt?
robots.txt: it fetches /robots.txt and, if that returns HTTP 200 as a text file, reads the Disallow lines in its first 8,000 characters. A Disallow path containing any of admin, internal, private, backup, config, staging, test, api, secret, dev is reported as low (CWE-200): robots.txt is public and only asks well-behaved crawlers to stay away, so listing those paths advertises them. Protect them with a login, and use noindex to keep pages out of search. security.txt: it requests /.well-known/security.txt, the location set by RFC 9116, and counts it in your favour when the file has a Contact: line. A missing file is not marked down. RFC 9116 also requires an Expires: field, which the scan does not check, so publish both, for example Contact: mailto:security@your-site, Expires: 2027-06-30T23:00:00Z. Check it yourself with curl -s https://your-site/.well-known/security.txt
What does the CAA check look for, and how do I add a CAA record?
It looks up CAA records (RFC 8659) for the host name you entered, over Cloudflare DNS-over-HTTPS. If any are found the check passes and the evidence shows up to 5 of them; if none are found it reports "No CAA record" as low, because then any public certificate authority may issue a certificate for the name. A CAA record lists the CAs you actually use, for example your-site. IN CAA 0 issue "letsencrypt.org", plus 0 iodef "mailto:security@your-site" to receive reports. Add one issue line per CA you use, and an issuewild line if wildcard certificates should come from a different CA. Check it yourself with dig CAA your-site
Why does scanning www or a subdomain report no CAA, SPF or DMARC?
Every DNS check runs on the exact name you entered, so www.example.com is looked up as www.example.com, not example.com, and the three records inherit differently. CAA: a certificate authority that finds no CAA record on www.example.com moves up to example.com and uses that one (RFC 8659 section 3), so "No CAA record" on a subdomain can be a false alarm. DMARC: receivers fall back to the policy of the organizational domain, which can set a separate subdomain policy with sp= (RFC 9989, which obsoletes RFC 7489), so a missing record at _dmarc.www.example.com is usually covered by _dmarc.example.com. SPF: there is no inheritance (RFC 7208), so "No SPF record" is accurate for that name; a host name that sends no mail can publish v=spf1 -all. A DNS lookup that fails also shows as no record. Scan the bare domain as well, or confirm with dig CAA example.com and dig TXT _dmarc.example.com