Website security checklist

24 items, each with a command to check it yourself.

Every item below can be verified from outside your site in one line, so you never have to take anyone's word for it — including ours. Each one also names the check that watches it automatically, and the last section lists the five controls that matter most and that no external scan can see.

The checkup runs the same reads on every item in the first six groups. It asks for a free account before showing the report, takes no card, and will not scan banks, government sites or the major platforms.

Group 1 of 6

Transport

Whether a visitor reaches you without a browser warning, and whether the connection can be tampered with in between.

  1. Serve the whole site over HTTPS, with a valid certificate

    An expired or mismatched certificate is a full-page interstitial. Most visitors do not click through one, and the ones who do learn that your warnings mean nothing.

    Check it yourself

    echo | openssl s_client -servername yourdomain.com -connect yourdomain.com:443 2>/dev/null | openssl x509 -noout -enddate

    In the DomainGuard report: HTTPS connection

  2. Redirect every HTTP request to HTTPS

    A site that answers on plain HTTP hands the first request to whoever is on the network. Redirecting is one rule and it closes that.

    Check it yourself

    curl -sI http://yourdomain.com | head -n 1

    In the DomainGuard report: HTTP to HTTPS redirect

  3. Send an HSTS header with a long max-age

    HSTS tells the browser to refuse plain HTTP for this name in future, which removes the redirect as an attack point rather than just using it.

    Check it yourself

    curl -sI https://yourdomain.com | grep -i strict-transport-security

    In the DomainGuard report: HSTS max-age

  4. Remove mixed content

    One script or stylesheet loaded over HTTP on an HTTPS page is a script an attacker on the same network can replace. The padlock stays, and the page is no longer yours.

    Check it yourself

    Open the page, then look at the browser console for mixed-content warnings.

    In the DomainGuard report: Mixed content

Group 2 of 6

Security headers

Nine headers, set in one place, that cost nothing and turn several classes of bug into a non-event.

  1. Set a Content-Security-Policy

    The one that does the most work. It limits where scripts, styles and frames may come from, which is what stops an injected script from reaching anywhere useful.

    Check it yourself

    curl -sI https://yourdomain.com | grep -i content-security-policy

    In the DomainGuard report: Content-Security-Policy

  2. Set X-Frame-Options, or a CSP frame-ancestors directive

    Stops your login or checkout page being loaded inside somebody else's page and clicked through invisibly.

    Check it yourself

    curl -sI https://yourdomain.com | grep -iE 'x-frame-options|frame-ancestors'

    In the DomainGuard report: X-Frame-Options

  3. Set X-Content-Type-Options: nosniff

    Stops the browser guessing that an uploaded file is really a script. One header, no configuration.

    Check it yourself

    curl -sI https://yourdomain.com | grep -i x-content-type-options

    In the DomainGuard report: X-Content-Type-Options

  4. Set a Referrer-Policy and a Permissions-Policy

    Referrer-Policy stops your internal URLs leaking to every site you link to. Permissions-Policy turns off camera, microphone and geolocation for anything embedded in your pages.

    Check it yourself

    curl -sI https://yourdomain.com | grep -iE 'referrer-policy|permissions-policy'

    In the DomainGuard report: Referrer-Policy

Group 3 of 6

Files that should not be there

The fastest category to turn into an incident, because there is nothing to exploit. The file is simply reachable.

  1. Confirm .env is not served

    A .env file holds live database credentials, API keys and mail passwords. It is the single highest-value file on most small business sites.

    Check it yourself

    curl -s -o /dev/null -w "%{http_code}\n" https://yourdomain.com/.env

    In the DomainGuard report: .env files

  2. Confirm the .git folder is not served

    An exposed .git directory can be reassembled into your entire source history, including whatever secret was committed once and removed in the next commit.

    Check it yourself

    curl -s -o /dev/null -w "%{http_code}\n" https://yourdomain.com/.git/HEAD

    In the DomainGuard report: Git folders

  3. Move backups and database dumps out of the web root

    backup.zip and site.sql sitting next to index.php are guessable, and the scanners guessing them are automated.

    Check it yourself

    curl -s -o /dev/null -w "%{http_code}\n" https://yourdomain.com/backup.zip

    In the DomainGuard report: Backups

  4. Turn off debug pages and stack traces in production

    A framework debug page prints file paths, environment variables and sometimes credentials to anyone who triggers an error.

    Check it yourself

    Request a URL that does not exist and read what comes back.

    In the DomainGuard report: Debug pages

Group 4 of 6

Email authentication

Three DNS records that decide whether your mail is delivered and whether anyone else can send as you.

  1. Publish an SPF record that ends in -all

    A record ending in ~all is a soft fail and is widely treated as a shrug. Ending in -all is the one that means something. Watch the 10-DNS-lookup limit while you do it: over it, the result is permerror and everything fails.

    Check it yourself

    dig +short TXT yourdomain.com | grep spf1

    In the DomainGuard report: SPF policy strength

  2. Publish DKIM keys for every service that sends mail as you

    DKIM survives forwarding where SPF does not, so it is the record that keeps your mail authenticated through mailing lists and forwarding rules.

    Check it yourself

    Ask each sending vendor for its selector, then: dig +short TXT selector._domainkey.yourdomain.com

    In the DomainGuard report: DKIM

  3. Publish a DMARC record, starting at p=none with a reporting address

    It changes nothing about delivery and starts a daily feed naming everyone who sends mail as your domain. Without it, you have no way to know.

    Check it yourself

    dig +short TXT _dmarc.yourdomain.com

    In the DomainGuard report: DMARC

  4. Lock down domains that send no mail

    Parked domains, old brand names and redirect domains are spoofed precisely because nobody watches them. SPF -all, DMARC p=reject and a null MX close that off in three records.

    Check it yourself

    dig +short MX yourparkeddomain.com

    In the DomainGuard report: MX records

Group 5 of 6

The domain and DNS underneath

The layer that takes the website and the email down together when it fails.

  1. Know the real expiry date, from the registry

    The registrar dashboard is a cached view. Since January 2025 the definitive source for generic top-level domain registration data is RDAP.

    Check it yourself

    curl -s https://rdap.org/domain/yourdomain.com | grep -A2 expiration

    In the DomainGuard report: Expiry date

  2. Point the registrant email at a role mailbox two people read

    Every ICANN-required expiry notice goes to the registrant address on the registration record. On an old domain that is usually somebody who left.

    Check it yourself

    Check the registrant contact in your registrar account.

    In the DomainGuard report: Registrar

  3. Turn on registrar lock and 2FA at the registrar

    Control of the registrar account is control of the domain, which is control of your email, which is control of every password reset you own.

    Check it yourself

    curl -s https://rdap.org/domain/yourdomain.com | grep -i clienttransferprohibited

    In the DomainGuard report: Registrar

  4. Use more than one nameserver, ideally on separate infrastructure

    A single nameserver is a single point of failure for the website and the mail at the same time.

    Check it yourself

    dig +short NS yourdomain.com

    In the DomainGuard report: Nameserver redundancy

  5. Check whether your sending IP is on a blacklist

    A DNSBL listing is a common reason mail suddenly lands in spam, and you will never find it by looking at your own inbox.

    Check it yourself

    Run the free checkup, which queries the common DNSBLs for you.

    In the DomainGuard report: IP blacklists (DNSBL)

Group 6 of 6

What the site gives away

Version numbers and cookie flags. Small, and they decide how you appear in somebody else's target list.

  1. Stop advertising server and framework versions

    Nobody scans by hand. Disclosed versions are matched against published vulnerabilities at scale, within days of a release.

    Check it yourself

    curl -sI https://yourdomain.com | grep -iE '^server:|^x-powered-by:'

    In the DomainGuard report: Server version exposure

  2. Set Secure, HttpOnly and SameSite on session cookies

    A session cookie without HttpOnly can be read by any script that reaches the page. Without Secure it can be sent over plain HTTP. Both are one-line changes.

    Check it yourself

    curl -sI https://yourdomain.com | grep -i set-cookie

    In the DomainGuard report: Cookie Secure

  3. Know which subdomains exist, including the ones you forgot

    Publicly trusted certificates must be logged to be trusted, so every subdomain that ever had HTTPS is in the public record. The forgotten staging site is a classic way in, and an attacker already has this list.

    Check it yourself

    Search a public Certificate Transparency index such as crt.sh for your domain.

    In the DomainGuard report: Subdomains (Certificate Transparency)

What no scan can see

Five controls that matter more than anything above.

These are listed separately because we cannot check them, and any tool that implies otherwise is selling you a false green tick. They are also, item for item, the highest-value work on this page.

  1. Test a restore, not just a backup

    A backup job that reports success and a backup that restores are different claims. Restore one to a scratch environment and open the data. This is the control that decides whether a ransomware incident is a bad week or the end of the business, and no scanner can verify it for you.

  2. Multi-factor authentication on the four accounts that matter

    Email, the domain registrar, DNS, and hosting. In that order. Verizon's annual Data Breach Investigations Report has, edition after edition, put stolen credentials and phishing among the most common ways an intrusion starts, and MFA on these four is the cheapest thing on this page.

  3. Patch on a schedule, and prioritize by exploitation

    CISA publishes the Known Exploited Vulnerabilities catalog: vulnerabilities with reliable evidence of active exploitation, each with a required action. Anything of yours on that list goes first, before anything with a higher CVSS score that nobody is actually attacking.

  4. Remove access when people leave

    Former staff, former contractors, former agencies. Check the CMS, the hosting panel, the registrar, the DNS provider and any shared mailbox. Nothing external can see this, and it is the account that never gets noticed.

  5. Write down who to call

    One page: hosting provider and account number, registrar and account, DNS provider, whoever built the site, and your insurer's incident line if you have cyber cover. Written before you need it, stored somewhere that does not depend on the systems that are down.

Questions people actually ask

How long does this checklist take?

The verification commands take about twenty minutes for one domain. Fixing what they turn up is the variable part: security headers and cookie flags are usually a single configuration change, email authentication takes a couple of weeks because you have to find and authenticate every sender, and moving backups out of a web root takes five minutes.

Do I need to be technical to use it?

The commands need a terminal, and most of them are a single line you can paste after swapping in your domain. If that is not you, run the free checkup instead — it performs the same reads and gives you the results in a report you can hand to whoever runs your site.

Which items matter most?

Three, in order. An exposed .env or .git folder, because that is credentials rather than a weakness. Multi-factor authentication on email and the registrar, because those two accounts control everything else. And a restore you have actually tested. Everything else on this page is real, and none of it is as load-bearing as those.

Does the free checkup cover all of this?

It covers everything in the first six groups, because those are all readable from outside without installing anything. It cannot cover the last group (backups, MFA, offboarding, patch cadence), and no external scan can. Those are listed separately here for exactly that reason.

What does it cost to have this watched?

A free account holds unlimited domains and runs the checkup whenever you press scan, keeping every result so the next one is a comparison. Automatic re-checking starts at Starter, $6.99 a month or $69.99 a year for 25 domains, bought through Apple in-app purchase. Free accounts still get dark-web breach checks and an alert when a vulnerability is published for software found on your sites.