To secure a website, serve it only over HTTPS with HSTS, keep the CMS, plugins and server software patched, and put multi-factor authentication and least privilege on every admin account. Add a web application firewall, keep backups outside the hosting account and test them, send security headers, protect the domain and email, and scan and monitor the site.
This checklist is for site owners and the small teams that run their sites, on WordPress, another CMS, a hosted builder or a custom application. It goes in the order that closes the most risk first, says what each control does not cover, and dates the figures that change. Developer practices such as input validation and parameterized queries are in our guide to secure coding best practices; this post is about running the site.
What website security has to cover
You do not need to be a target to be attacked. Automated tools sweep the internet for known flaws, and a site gets hit because it runs a vulnerable plugin or accepts a reused password, not because of who owns it. So the work is the same for every business: remove the easy ways in, limit what a stolen account can do, and make sure you would notice, and recover, if something got through.
The OWASP Top 10, the standard awareness list of the most critical web application risks, is now in its 2025 edition. Several of its categories are about how a site is run, not only how it is coded:
- A01 Broken access control: someone reaches data or functions they should not. It holds the top position, and OWASP found some form of it in every application tested.
- A02 Security misconfiguration, which explicitly includes a server that sends no security headers, or sends them with weak values.
- A03 Software supply chain failures: vulnerable, unmaintained or compromised third-party components. On most sites that means plugins, themes and packages.
- A07 Authentication failures, including sites that allow credential stuffing (automated sign-ins with passwords leaked elsewhere) or lack effective multi-factor authentication.
- A09 Security logging and alerting failures: without logs and alerts, a breach is neither detected nor answered in time.
Before you start, settle who is responsible for each layer. The Canadian Centre for Cyber Security points out that with cloud services, who patches depends on the service model: with software as a service, the provider does.
| Where the site runs | Who patches the platform | What stays with you |
|---|---|---|
| Hosted site builder (SaaS) | The provider | Admin accounts and MFA, the domain, email, third-party scripts |
| Managed CMS hosting | The host, for the server and runtime; plugins depend on the contract | Plugins, themes, admin users, backups outside the host's own |
| Virtual or cloud server | You | Everything from the operating system up |
Serve every page over HTTPS, then turn on HSTS
HTTPS encrypts traffic between the browser and your server and proves the visitor reached your domain. Every page needs it, not only the login and checkout pages, because anyone who can alter one unencrypted page can send the visitor anywhere. Get a certificate for every host name you serve and automate its renewal; our guide to renewing an SSL certificate covers the steps, the tools and the shrinking certificate lifetimes. Then close the gaps around it:
- Redirect every
http://request to the same page onhttps://with a permanent (301) redirect, on the same host name. - Fix mixed content: images, scripts or form targets still loaded over
http://from an HTTPS page. - Send the
Strict-Transport-Security(HSTS) header on HTTPS responses.
HSTS tells the browser to use HTTPS for your domain from then on: it upgrades any later http:// link before sending it, and it stops offering visitors a way to click through a certificate error. Browsers ignore the header when it arrives over plain HTTP, so it only works on HTTPS responses. Its one weakness is the first visit, before the browser has seen the header; the HSTS preload list, built into browsers, closes that gap.
Roll it out in stages. The preload list's maintainers suggest starting with max-age=300 (five minutes), then a week, then a month, checking for broken pages at each stage before you settle on a long value. The OWASP Secure Headers Project proposes two years:
Strict-Transport-Security: max-age=63072000; includeSubDomains
Warning
includeSubDomains applies HSTS to every subdomain, and preloading goes further: it covers all subdomains, including internal ones that are not publicly reachable, and getting off the list is slow. Preload only when every host under the domain serves HTTPS and will keep doing so. The list requires a max-age of at least one year, includeSubDomains and the preload directive.
Browsers are moving the same way. In October 2025, Google announced that Chrome 154, due in October 2026, turns on "Always Use Secure Connections" by default, so Chrome will ask for the user's permission before the first visit to any public site without HTTPS. A site still on plain HTTP will meet many visitors with a warning before its first page loads. Search asks the same question: Google's page experience guidance lists whether your pages are served in a secure fashion among the checks for a good page experience.
Keep the CMS, plugins and dependencies updated
WordPress's own hardening guide warns that once a release fixes a vulnerability, the information needed to exploit it is almost certainly public, and that older versions get no security updates. The same logic applies to any CMS or library. The figures below are vendor data from Patchstack, which sells WordPress vulnerability protection, published in its State of WordPress Security in 2026 report on the year 2025:
- 11,334 new vulnerabilities were found in the WordPress ecosystem in 2025, 42% more than in 2024.
- 91% were in plugins and 9% in themes. WordPress core had 6, all low priority.
- 46% had no fix from the developer by the time they were disclosed publicly.
- For the most heavily exploited vulnerabilities, the weighted median time to the first exploitation attempt was 5 hours, and about half of high-impact vulnerabilities were exploited within 24 hours.
- Only four of the ten vulnerabilities attacked most in 2025 were published that year; the rest dated from 2023 and 2024, still present on the sites attackers went after.
The risk sits in everything installed around the core, so that is where the work goes:
- Turn on automatic updates where the platform supports them. WordPress has shipped automatic updates since version 3.7, and since 5.5 administrators can switch on auto-updates plugin by plugin and theme by theme; WordPress runs them twice a day.
- Stage the big ones. Major versions of the CMS, page builders and shop plugins go to a staging copy first, with a way back.
- Delete what you do not use. A deactivated plugin is still code on the server, and WordPress's guide says to delete plugins you are not using.
- Replace abandoned components. With almost half of vulnerabilities disclosed before a fix existed, a plugin whose developer has gone quiet is a liability. Install plugins and themes only from trusted sources.
- Patch the server too: the operating system, web server and runtime (PHP, Node.js, Python). A version past its end of life gets no security fixes at all.
- Watch dependencies in custom applications. Packages from npm, Composer or PyPI are the supply chain OWASP's A03 is about. GitHub's Dependabot security updates open pull requests that update a dependency with a known vulnerability; the rest of the developer side is in the secure coding guide.
When updates pile up, go by exposure and evidence. CISA's #StopRansomware Guide says to prioritize internet-facing servers and known exploited vulnerabilities, and CISA's Known Exploited Vulnerabilities (KEV) catalogue is its authoritative list of vulnerabilities that have been exploited in the wild. A full patch prioritization policy, with EPSS and deadlines, is in the future of cybersecurity.
Protect admin accounts with MFA and least privilege
A stolen admin password switches off most other controls: whoever holds it can install a plugin, add a user or change the payment page. OWASP's advice on authentication failures is to enforce multi-factor authentication (MFA) wherever possible, because it stops credential stuffing, brute force and the reuse of stolen passwords. Apply it to every account that can change the site, not only the CMS: the hosting panel, SFTP or SSH, the database console, the domain registrar and DNS provider, the CDN or WAF dashboard, the email platform and Google Search Console.
Choose the strongest factor people will actually use. CISA's fact sheet on phishing-resistant MFA says any MFA is better than none, but warns that some forms fall to phishing, push bombing (flooding a user with prompts until they approve one) and SIM swapping. It calls phishing-resistant MFA the gold standard and names FIDO/WebAuthn as the only widely available form. Security keys and passkeys both use it: the FIDO Alliance describes passkeys as FIDO credentials built on the FIDO2 specifications.
Passwords still matter where MFA is not offered. NIST's SP 800-63B-4 (July 2025) requires passwords used on their own to be at least 15 characters (8 when the password is one factor of MFA), and tells services not to impose composition rules or periodic changes, only a change when there is evidence of compromise. A password manager makes long, unique passwords practical, and OWASP recommends encouraging them.
Then cut privileges down. Least privilege means each account gets only the access its work needs, so a stolen account does limited damage. Among WordPress's built-in roles, an Administrator can use every administration feature of a site, an Editor publishes and manages everyone's posts, an Author manages only their own, and a Contributor can write but not publish. Most people who update content need Editor or less.
- One named account per person, never a shared login, so you can remove one person without changing everyone's password.
- Remove former staff, agencies and freelancers on the day their work ends.
- Put the admin area behind an extra gate where you can. The Canadian Centre for Cyber Security recommends isolating the administrative interface and having remote administrators connect through a VPN; an IP allowlist is a lighter version of the same idea.
- Disable the built-in code editor. On WordPress,
define( 'DISALLOW_FILE_EDIT', true );inwp-config.phpremoves the dashboard's theme and plugin file editor. WordPress notes it will not stop someone uploading malicious files, but it closes one easy route from a stolen admin session to running code.
Put a web application firewall in front, and know its limits
A web application firewall (WAF) works as a reverse proxy for HTTP: it checks each request against a set of rules, mostly written for common attacks such as SQL injection and cross-site scripting, and blocks the ones that match. It comes in three forms:
| Where it runs | How it works | Examples |
|---|---|---|
| At the edge | A service in front of your host; you point your DNS records at it | The WAF of your CDN or security provider, such as Cloudflare |
| On the web server | A module that filters requests before the application sees them | ModSecurity or OWASP Coraza with the OWASP CRS rule set |
| In the application | A plugin that filters requests while the CMS loads | WordPress firewall plugins such as Wordfence and Shield |
The OWASP CRS rule set covers SQL injection, cross-site scripting, file inclusion, code and shell injection and scanner detection, among others. Whatever the form, rules need tuning so they do not block real visitors, and upkeep as the site changes.
A WAF's most valuable job on a small site is buying time. The Canadian Centre for Cyber Security describes it as a short-term stopgap: when a vulnerability is found, a WAF rule can block the attack until the fix is deployed. OWASP calls this virtual patching, and is clear that fixing the code remains the first remedy; the two run side by side. What a WAF does not stop matters just as much:
- Valid sign-ins with stolen passwords. A login with the right password is a normal request. MFA stops it; a WAF does not.
- Broken access control and logic flaws. In Patchstack's 2025 vendor data, broken access control was the most exploited class of WordPress vulnerability, and the company notes these exploits look like normal authenticated traffic, with no injection pattern for a rule to match.
- Flaws its rules do not know. In two 2025 penetration-testing studies, Patchstack found that common hosting defences, including in-house WAFs and Cloudflare, blocked 12% of attacks on known exploited WordPress vulnerabilities in the first and 26% of attacks in the broader second. Those are figures from a vendor that sells its own protection rules, but they make the same point: a WAF is a layer, not a patch.
- Traffic that goes around it. An edge WAF protects only the requests that pass through it. Anyone who finds your server's own IP address can connect to it directly. Cloudflare's documentation recommends accepting traffic only from its IP ranges, or using authenticated origin pulls or a tunnel, and rotating the origin IP after onboarding, because historical DNS records keep the old one.

Keep backups somewhere else, and prove them by restoring
Backups turn a breach, a failed update or ransomware into an inconvenience instead of a rebuild. CISA's #StopRansomware Guide asks for offline, encrypted backups of critical data, tested regularly for availability and integrity in a disaster recovery scenario, because many ransomware variants look for reachable backups and delete or encrypt them first. For a website, that means:
- Back up everything needed to rebuild: the database, uploaded media, the code or theme, and the configuration. Encrypt the backups, since configuration files hold secrets.
- Keep at least one copy outside the hosting account, under different credentials, so one stolen hosting login cannot delete the site and its backups together. CISA also suggests considering a second cloud provider, in case every account with one vendor is affected.
- Make one copy offline or immutable. CISA mentions the immutable storage some cloud vendors offer, with two cautions: a misconfiguration can be costly, and it does not meet every regulation's criteria.
- Keep history. An infection can go unnoticed for a while, so keep enough older versions to go back to a clean one. WordPress's hardening guide adds that a separate record of each backup's checksum, or read-only media, shows a backup has not been tampered with.
- Restore on a schedule. Restore a recent backup into a separate staging environment, check that pages, sign-ins and forms work, and time it.

The restore test gives you two numbers: how long recovery really takes (your recovery time) and how much you would lose between backups (your recovery point). Agree both with whoever depends on the site before you need them.
Important
A backup you have never restored is an assumption. The first real restore should not happen on the day the site is down.
Send security headers
Security headers are instructions your server sends with each response, telling the browser to refuse behaviour your site never needs. They cost little to add, and OWASP counts a server that sends none, or sends weak values, as security misconfiguration (A02:2025). The OWASP Secure Headers Project maintains a proposed set; these are the ones to start with, as MDN describes them:
| Header | What it does | Starting value |
|---|---|---|
Strict-Transport-Security | HTTPS only on future visits, no clicking through certificate errors | max-age=63072000; includeSubDomains |
Content-Security-Policy | Lists where scripts, styles, images and frames may load from, which guards against cross-site scripting | Report-only first (below) |
frame-ancestors (a CSP directive) | Says which sites may embed your pages in a frame, which prevents clickjacking | frame-ancestors 'self' or 'none' |
X-Frame-Options | The older header for the same job, still honoured by older browsers | DENY or SAMEORIGIN |
X-Content-Type-Options | Makes the browser trust the declared content type, and block scripts and stylesheets with the wrong one | nosniff |
Referrer-Policy | Controls how much of the page address is sent in the Referer header with requests | The OWASP proposal is no-referrer |
Content Security Policy is the most powerful header and the one most likely to break something, because a CMS page often loads scripts from plugins, analytics and chat widgets. Roll it out in two steps. First send the policy as Content-Security-Policy-Report-Only, which reports violations without blocking anything (it needs a report-to endpoint to send the reports). Fix or allow what legitimately loads, then switch to the enforcing Content-Security-Policy header. The OWASP proposal is a strict starting point: default-src 'self'; form-action 'self'; base-uri 'self'; object-src 'none'; frame-ancestors 'none'; upgrade-insecure-requests.
On nginx, a baseline looks like this:
server {
add_header Strict-Transport-Security "max-age=63072000; includeSubDomains" always;
add_header X-Content-Type-Options "nosniff" always;
add_header Content-Security-Policy "frame-ancestors 'self'; object-src 'none'; base-uri 'self'" always;
}
always adds the header to error responses too. Watch the inheritance rule: a location block inherits add_header directives from its parent only if it defines none of its own, so one add_header inside a location silently drops all the others (nginx 1.29.3 added add_header_inherit to change that).
Also drop what no longer helps. The Secure Headers Project lists X-XSS-Protection, Expect-CT, Public-Key-Pins and Feature-Policy as deprecated, and recommends X-XSS-Protection: 0 if the header is still sent. It suggests removing headers that advertise your software and versions, such as Server and X-Powered-By. If the site is being rebuilt, make headers part of the launch: our web design and development work puts security headers and a strict Content Security Policy in the definition of done.
Make file uploads and forms safe
Any form that accepts a file lets a stranger put something on your server. The Canadian Centre for Cyber Security's first question is whether you need uploads at all: a job application may work as well with form fields as with an attached CV. Where uploads are needed, OWASP's File Upload Cheat Sheet sets out the controls. On a CMS, most of them are settings in the form or media plugin, not code:
- Allow only the file types the business needs, for example PDF and DOCX for a CV, and do not trust the file's declared type, which is trivial to fake.
- Set a size limit.
- Let only authorized users upload where the use case allows it.
- Rename files on upload and store them outside the web root, or on a separate storage service, so an uploaded file can never run as code on your server.
- Scan uploads with antivirus or a sandbox, and keep the upload plugin and its libraries up to date.
This is not theoretical: in Patchstack's vendor data, one of the ten WordPress vulnerabilities attacked most in 2025 was an unauthenticated arbitrary file upload in a page-builder add-on.
Forms without files need protection from abuse. The Cyber Centre recommends account lockouts, login delays and CAPTCHAs against brute force on sign-in, plus alerts on failed login attempts; apply the same thinking to password reset and contact forms, and collect only the fields you need. How the application should validate what forms submit is developer work, covered in the secure coding guide.
Protect your domain and email
Your domain is the root of everything else: whoever controls its DNS can point your website and mail anywhere. In January 2019, CISA described exactly that campaign. Attackers stole the credentials of accounts that could edit DNS and changed address, mail and name server records to redirect web and mail traffic. With control of DNS, an attacker can also obtain valid certificates, so redirected traffic can be decrypted without a single browser warning. CISA's emergency directive told US federal agencies to audit their DNS records, change DNS account passwords, add MFA and watch Certificate Transparency logs for certificates they had not requested. For any business, that becomes:
- MFA on the registrar and DNS accounts, with the domain registered in the business's name and a contact address someone still reads.
- Registrar locks. ICANN notes that asking your registrar for
clientTransferProhibited,clientDeleteProhibitedandclientUpdateProhibitedhelps prevent unauthorized transfers, deletions and updates. - Auto-renewal on the domain, paid with a card that will not expire unnoticed.
- A regular check that DNS records point where you expect, and a Certificate Transparency monitor that alerts you to new certificates for your domain.
Email is the other half. Without authentication, anyone can send mail that claims to come from your domain. Three DNS-based standards fix that together:
- SPF (RFC 7208) lists the servers allowed to send mail for your domain. Evaluating a record may use at most 10 DNS-querying terms (
include,a,mxand similar); past that, the check fails with a permanent error, which is easy to hit once several mail services are added. - DKIM (RFC 6376) signs each message with a key whose public half is published in your DNS, so the receiver can verify which domain took responsibility for it.
- DMARC ties both to the address people see: a message passes only if SPF or DKIM passes for a domain aligned with the
From:domain. Your policy tells receivers what to do with failures (none,quarantineorreject) and where to send aggregate reports. In May 2026, DMARC moved onto the IETF Standards Track as RFC 9989, which replaces the earlier informational RFC 7489.

RFC 9989 sets out the order for a domain owner: publish SPF, sign with DKIM, set up a mailbox for aggregate reports, publish a DMARC record with p=none (monitoring mode), read the reports, fix every legitimate sender that fails, then decide whether to move to enforcement.
example.com. TXT "v=spf1 include:_spf.mail-provider.example -all"
_dmarc.example.com. TXT "v=DMARC1; p=none; rua=mailto:dmarc-reports@example.com"
Large mailbox providers now require this. Since February 1, 2024, Gmail has required SPF or DKIM from every sender, and SPF, DKIM and DMARC (a p=none policy is enough) from anyone sending more than 5,000 messages a day to Gmail accounts. Outlook.com applied the same three requirements to domains sending more than 5,000 messages a day from May 5, 2025, routing non-compliant mail to Junk first. Email and domain checks (DMARC, SPF and DKIM, MTA-STS, DNSSEC and registrar lock) are part of our security testing service.
Keep DDoS attacks away from your server
A distributed denial-of-service (DDoS) attack does not break in; it floods the site until real visitors cannot reach it. A single server cannot absorb a large flood by itself, so the protection has to sit upstream: a CDN or host with DDoS protection in front of the site, caching so most requests are answered without touching the server, and rate limits on expensive pages such as login and search. The Cyber Centre also lists slowing denial-of-service attacks among the jobs a WAF can do. The origin rule from the WAF section applies here too: if the server accepts traffic from anywhere, attackers who find its address skip the protection entirely. How the attacks work, and how DDoS protection absorbs them, is in our explainer on DDoS attacks.
Monitor, log and scan your own site
Prevention sometimes fails; what matters then is how soon you know. OWASP's A09:2025 puts it plainly: without logging and monitoring, attacks and breaches cannot be detected, and without alerting it is very hard to respond quickly. Watch these, and send the alerts to a named person, not a shared inbox nobody reads:
- uptime and key pages, checked from outside your hosting
- certificate and domain expiry dates
- admin sign-ins, failed sign-ins, new admin users and newly installed plugins or themes
- changes to files that should not change, such as core files and
.htaccess; WordPress's hardening guide recommends monitoring files for changes because attacks leave traces in the logs or on the file system - WAF events and server error logs
Keep logs where the web server cannot rewrite them, because an intruder with access may try to clean up. OWASP asks for audit trails with integrity controls that prevent tampering or deletion.
Add the site to Google Search Console. Its Security Issues report lists signs that the site was hacked or could harm visitors, such as malware or phishing pages, which can carry a warning label in search results or trigger a browser warning. Google tells owners to treat the report as the source of truth. Some infections are hard to see any other way: Patchstack's report describes malware that shows clean pages to site owners and security scanners while redirecting other visitors.
Then scan your own site on a schedule and after major changes. The Canadian Centre for Cyber Security recommends building vulnerability scanning into deployment, with tools such as the open-source OWASP ZAP (Zed Attack Proxy). Free checks worth running from outside:
- MDN's HTTP Observatory assesses a site's HTTP headers and other key security settings.
- Qualys SSL Labs' SSL Server Test analyzes the TLS configuration in depth.
- ZAP scans a web application for vulnerabilities; point it at staging first.
Only scan sites you own or have written permission to test. And publish a security.txt file (RFC 9116) at /.well-known/security.txt, with a Contact line and an Expires date less than a year ahead, so a researcher who finds a problem knows how to tell you.
When scanning needs to be continuous and triaged rather than occasional, our security testing service runs scheduled external scans of websites, servers and cloud accounts, triaged by engineers and closed with a re-test.
A website security checklist to run on a schedule
Security is upkeep, not a project with an end date. This is the rhythm that keeps a small site in shape:
- Always on: automatic updates, scheduled backups, and uptime, certificate and domain expiry alerts that reach a person.
- Every week: confirm the automatic updates applied, stage and apply the ones that need testing, and read security alerts and WAF events.
- Every month: review admin users and remove the ones nobody needs, delete unused plugins and themes, and read the DMARC aggregate reports.
- Every quarter: restore a backup into staging and time it, run the header and TLS checks and an external scan, and audit DNS records and registrar settings.
- Every year: review this list against the current OWASP Top 10, move the
Expiresdate insecurity.txtforward, and consider a penetration test before a major launch.
If keeping up with that list is the problem, our hosting and maintenance service covers the running side: operating system, runtime, CMS and plugin updates, backups with scheduled restore drills, uptime and certificate monitoring, and CDN, WAF, TLS and security header configuration.


