Skip to content
>_ITDITDWeb Security Platform

Security Guides

Common security mistakes are failures of assumption, not of skill — four beliefs that keep breaking

Real incidents rarely involve exotic attacks. Sorted by the assumption behind them, the causes come down to four beliefs — and each was true once, which is why nobody re-examines them.

Published 2026-09-05 Updated 2026-09-05 Last verified 2026-09-05 9 min read

Line up the incidents that actually happen and exotic attack techniques barely appear. What appears is a small set of recurring shapes — and those shapes are clearer when sorted not by technology but by the assumption behind them.

① "Defaults must be safe" — nothing was configured

Defaults chosen for ease of development

detailed errors · admin surfaces reachable · broad permissions

↓ shipped unchanged

A signpost for whoever is looking

structure, paths, versions and internal values become readable

A default is a value that is unobjectionable for everyone — not a value that is safe for your production.
What this shape looks like, and what to check
Debug output enabled in production
Do error pages expose environment variables, file paths or stack traces? Open a URL that does not exist and look at what comes back with your own eyes. Framework specifics live in the framework guides
Administrative surfaces reachable
Database management tools and admin consoles reachable from the internet. Do not rely on authentication alone — layer IP restrictions or network-level blocking
Headers unset, or copied from a stale list
See which headers still matter and which do not. A deprecated header can do harm if you add it
Weak storage left in place
Password storage as described in hashing and salting. "It's encrypted" is not a description of a storage scheme
Updates have stopped
Running a language, framework or CMS past its supported life. See machine-monitoring dependencies and what end of support actually means

② "Unused things must be harmless" — nothing was closed

Attack surface grows out of what you retired, not what you built. The moment something stops being used, it quietly drops out of monitoring and review.

What this shape looks like, and what to check
Secrets left in a public directory
.env, backups, dumps, config files. what must never sit in a public directory / placement on shared hosting
Storage still public
Turning blocking on does not delete the existing public policy. public buckets
Dangling DNS records
Delete a resource without the DNS entry and anyone can claim the name and take the subdomain. subdomain takeover
Registration and admin paths left open
Is open registration still enabled? Measure it over HTTP rather than reading the config (authentication vs authorization). Do not leave a guessable URL as the only thing "hiding" a page
Accounts you thought were cancelled
Cancelling a service and deleting the account are different, and data stays until you delete. when your hosting provider is breached
Old keys, tokens and permissions
Departed colleagues' accounts, tokens with no expiry, over-broad scopes. SSH keys and least privilege / password managers

Do not scope the inventory to what is running

Limit your review to "things currently in use" and this shape becomes structurally invisible. Scope it to everything you ever created — subdomains, accounts, keys, buckets, staging environments, third-party subscriptions. Something you stopped using is still an asset until it is deleted. How to build the list: the asset inventory checklist.

③ "We would notice" — nothing is observable

Damage is determined less by the breach itself than by how long it runs before anyone notices. And most environments have no mechanism for noticing.

The usual state

・Access logs exist but nobody reads them
・No audit log of authentication attempts (so "what was seen" cannot be reconstructed afterwards)
・Rate limits are configured but nobody can see when they trigger
・Public status is the composition of several layers, so no single one answers the question

The end state is being able to say only "we don't know" about whether anything happened.

The minimum worth having

A notification on new user registration (one signal is enough to catch the odd one)
A record of authentication successes and failures, with a retention period
Machine monitoring of dependency vulnerabilities (people cannot track this → osv-scanner)
A record of limit hits, and an alert on a spike (rate limiting and abuse control)

You do not need all of it. One working path to noticing is what stops an incident from becoming a long one.

With no logs, the honest answer is "we don't know", not "nothing happened"

The most dangerous move in incident response is reading an absence of records as evidence that nothing occurred. With no records, the only supportable statement is "we don't know" — and in that case, proceed on the assumption of compromise and rotate whatever could have been exposed. The organisational floor is in the organisational security baseline.

④ "Validated input must be safe" — too much was delegated

The real question about an input is not "is this value correct" but "how much have I let this input decide". The more decisions you hand over, the less validation can keep up.

Sorted by the decision you have handed outside
Only the value
Ordinary input. Checks on length, format and range work — the safe side
The structure too
Designs that accept a whole nested object and merge it. prototype pollution
The type as well
Formats that reconstruct objects. It is settled before your value checks run. insecure deserialization
Where it lands
Uploads that end up somewhere they can be executed. file upload vulnerabilities
Who the request is
Trusting a request header to decide the client's identity. X-Forwarded-For spoofing and trusted proxies

Counting the decisions you have handed over surfaces the dangerous places on its own. And the underlying cause is usually the same: trying to solve in validation what should be solved in structure — changing the shape you accept is more reliable than adding another check.

Doing it in order

1

Look at how production actually appears (①)

A URL that does not exist, a request that errors, the administrative paths — hit them over HTTP and look at what comes back. The point is to read the output, not the configuration. Headers can be measured in one go with the header scanner.

2

Write down everything you ever created (②)

Subdomains, accounts, keys, buckets, third-party services. The trick is not to filter by "still running". Build the list with the asset inventory checklist, and take unused entries all the way to deletion (not merely disabled).

3

Build exactly one path to noticing (③)

Trying to stand up complete monitoring usually results in none at all. Start with one — new-registration notifications, a spike in failed logins, or dependency vulnerability mail. One, including confirming it actually fires (monitoring that was configured but never verified is monitoring you do not have).

4

Count what your inputs are allowed to decide (④)

Write out whether external data decides only values, or also structure, type and destination. Anywhere it decides more than values is a high-priority place to change.

5

Make updates a mechanism (so ① does not come back)

The first shape reliably returns if left alone. Putting dependency and framework updates under machine monitoring is the only realistic answer (getting started with osv-scanner / a practical CVE remediation playbook). A procedure that lives in a document is the first thing to go on a busy day.

This site's view: all four were true once

What the four have in common is that each was correct at some point. Defaults were reasonable during development; unused things genuinely were unused; while you were small you really would have noticed; and input validation has solved a great many problems. That is exactly why they go unexamined.

Our position is to periodically ask when a formerly correct assumption stopped being correct. That check is cheaper and more effective than adding more technology. And note the difference in kind: a checklist tells you what to do, but not why something was missed — and if the reason is unchanged, the same gap reopens in the same place.

FAQ

QWhere should I start with security?
A

Checking which of four shapes your own environment matches works faster than learning individual attack techniques. Are production settings still at their defaults? Is anything still open that you created and never closed? Would you notice if something went wrong? How much are you letting external input decide? This article gives the concrete checks for each and links to the deeper articles.

QDoes this apply to a small personal site?
A

The shapes are the same; the ordering changes. For an individual or a small team, the two that pay off first are checking defaults (is debug output enabled in production?) and inventorying what was never closed (secrets in a public directory, unused subdomains, dormant accounts). Observability needs machinery so it can wait — but even a single signal, such as a notification on new user registrations, dramatically shortens how long a problem goes unnoticed.

QHow is this different from a checklist?
A

A checklist tells you what to do; this is about why things get missed. Listing items does not help if the reason they were missed is unchanged — the same gap reopens in the same place. All four beliefs were true once, which is exactly why they survive unexamined. When you want the actual steps, follow the links to the checklist articles from each section.

QI only have time for one. Which?
A

Close one gap in the third — being able to notice. The first two turn into incidents if ignored, but without the third you will not know an incident happened. Damage is decided less by the breach than by how long it runs unnoticed. Keep a log, add one notification, do one inventory a month: any of those is the single highest-return investment against an incident becoming a long one.