Picture the site: five pages — home, services, area covered, about, contact. No shop. No customer logins. No comments. The last content change was a phone number, three years ago.
A build like that has, on my count, 43 distinct ways in. Not vulnerabilities — there need not be a single known exploit sitting open. Just doors: pieces of code that run when a stranger requests a page, endpoints anyone can send a request to, and credentials that would hand over the whole thing.
Counting the doors
An attack surface is not a score out of ten. It is a list. Here is the list, in three groups.
Code that executes on every request — 24
Nineteen plugins, one theme, WordPress core, PHP, the web server, and MySQL. Every one of those is software written by someone else that runs before your five paragraphs of text reach the reader. Most were chosen by whoever built the site, years ago, and have been updating themselves ever since.
A plugin is a door. Forty plugins is forty doors, each maintained by a stranger.
Endpoints anyone on the internet can reach — 7
/wp-login.php, /wp-admin/admin-ajax.php, /xmlrpc.php, the REST API at /wp-json/, the uploads directory, the search query, and a comment form left enabled on a site with no blog. Six of those seven exist to support features the business does not use.
The login page is the one worth sitting with. It is a form, on the public internet, that accepts unlimited guesses at your password, and it is at a URL every scanner on earth already knows. Server logs on sites like this routinely show four figures of login attempts a day. None of them are staff.
Credentials that would unlock it — 12
Two staff accounts, one agency admin account, the hosting control panel, SFTP, the database user, the domain registrar, the theme licence account, an email-sending key, a backup service key, a CDN account, and the inbox that all of those send password resets to.
One of those staff accounts almost always belongs to someone who left years ago. Still active, still an administrator, still using a password they also used somewhere else. It is the single most common thing I find.
24 + 7 + 12 = 43.
What each door was actually buying
| Feature | What was installed | What the site needed |
|---|---|---|
| Contact form | Plugin, database table, admin screen | Nine lines of HTML |
| Image gallery | Plugin with its own JS bundle | Six <img> tags |
| SEO | Plugin, 2 MB, nags weekly | A title and a description |
| Caching | Plugin, to speed up the plugins | Files are already fast |
| Security | Plugin, to guard the login page | No login page |
| Backups | Plugin, nightly, to off-site storage | The files are the backup |
Read the last three rows again. A caching plugin exists to make the plugins fast. A security plugin exists to guard a login page the business does not use. A backup plugin exists because the site's content lives in a database that can be corrupted. Each one is solving a problem created by the layer beneath it.
This is not a conspiracy. It is what happens when the default answer to "I need a website" is an application platform. The plugins are all reasonable choices given that starting point. The starting point is the thing worth arguing with.
What zero looks like
A static site is files on a disk that a web server hands to whoever asks. There is no code of yours running on the server, so there is nothing of yours to exploit. There is no database, so there is nothing to inject into. There is no login page, so there is nothing to guess at.
You are not down to zero risk — nobody is. Your host can be breached, your domain can be hijacked at the registrar, and your DNS can be pointed somewhere else. Those risks exist for every site on the internet, including this one. What goes away is the entire middle category: the twenty-four pieces of somebody else's code, and the seven endpoints that exist to serve features you do not use.
Ways in, on the build described above.
24 + 7 + 12, itemised above
Login attempts a day. Unremarkable for an exposed admin page.
Order of magnitude, from server logs
Of those doors survive a static rebuild.
Static HTML, no server code
If you are not rebuilding today
Three things that cost nothing and shrink the list this afternoon:
- Remove the accounts of people who have left. Not "demote to subscriber" — remove. Then turn on two-factor for the rest.
- Delete plugins you do not use rather than deactivating them. Deactivated plugin code still sits on the disk and is still a file the web server can be tricked into reaching.
- Turn off what the site does not do. No blog means no comments. No app integrations means no XML-RPC.
None of that is a rebuild. It just makes the list shorter while you decide.
What the rebuild costs, and what it saves, is in the five-year bill nobody quotes you.
Get the next teardown.
One email when there is a new post. No drip sequence, no webinar, no course.
Posts to a form service. No database, no plugin, no cookie banner.