The first website I ever made secure was a mistake. I added HTTPS. I thought I had done a great job, so I just moved on. Three months later a security researcher told me in a way that my website was not secure at all. It was actually giving away customer information through an API endpoint that I had forgotten about and left unprotected.
That was a lesson for me. Making a website secure is not about doing one big thing. Security is about paying attention to all the details, like the website and its security. The website security is what matters. I should have taken care of the website security from the start. It's about the mundane, repetitive, unsexy work of checking boxes before every launch. The pros don't have secret knowledge. They have checklists (8).
Here's what's actually on that checklist in 2026.
Phase 1: Authentication — The Front Door
Before you do anything else, lock the door properly. Most breaches start with stolen credentials, not zero-day exploits.⁷.
Kill passwords (or at least tame them). Passkeys are now the industry standard—5 billion in active use globally [citation: ?]. But if you must use passwords, follow the current NIST guidelines: minimum length trumps complexity. 3. A 15-character phrase is stronger than "P@ssw0rd1" and far more memorable.
Rate limit authentication attempts. The Singapore government's security standards recommend limiting to 3–5 failed attempts within 15 minutes. This simple control stops the vast majority of automated credential-stuffing attacks.
Implement proper password storage. Never store passwords. Store salted hashes using Argon2, scrypt, or PBKDF2–3. The salt should be randomly generated for each account—not reused, not predictable.
Enforce session management. Re-authenticate users after periods of inactivity. For sensitive systems, NIST recommends re-authentication every 12 hours or after 30 minutes of inactivity.³.
Phase 2: Authorization — Checking Every Request
Authentication tells you who someone is. Authorization tells you what they can do. Most API breaches happen because developers implement one and forget the other.
Implement object-level access control. This means checking that the user who is logged in actually owns the thing they are trying to get to.
You can test it yourself.
Capture a request. Then change the user ID or order ID in the URL or body.
See if the server still gives you the data.
If it does, then you have a problem called Insecure Direct Object Reference, or IDOR, for short.
IDOR is one of the common security flaws that can be easily prevented.
You should verify the authenticated user owns the resource they are trying to access.
Try changing the user ID or order ID. See what happens.
The server should not return data if the user ID or order ID does not match.
This is how you can prevent IDOR.
IDOR happens when a user can access something that does not belong to them.
You can prevent IDOR by verifying the user owns the resource.
This is a security check.
Make sure to test for IDOR.
It can help keep your data safe.
IDOR is a flaw.
You can prevent it by verifying the user.
The user ID and order ID should match.
If not, the server should not return data.
This helps keep the data secure.
Verify the user owns the resource.
This helps prevent IDOR.
IDOR is a flaw.
It can be prevented.
Just verify the user.
Make sure they own the resource.
Then you can prevent IDOR.
Deny by default. Start with no access and grant it explicitly. Never assume that because a user is authenticated, they're authorized for everything.².
Enforce access control checks on every request. Use authorization middleware or filters that force every authenticated request through the same verification logic. No exceptions, no "internal endpoints are safe" assumptions.
Apply least privilege. Service accounts should have only the permissions they need — nothing more. A reporting service shouldn't have write access. A frontend API key shouldn't have admin scopes.
Phase 3: Input Validation — Trust Nothing
Your application will receive malicious input. Attackers will test every field, every parameter, every header. Validate everything-3.
Use parameterized queries for all database operations. Never concatenate user input into SQL or NoSQL queries (3–7). SQL injection remains a top OWASP risk because developers keep making this mistake. Parameterized queries completely separate code from data.
Validate all inputs against a schema. Only properly formatted data should enter your system. Check types, lengths, formats, and ranges. 2. Reject anything that doesn't match. A good rule: if you can't write a regex for it, you probably shouldn't accept it.
Escape outputs for context. The type of encoding depends on where the data is being displayed—HTML, HTML attributes, JavaScript, or URLs. Each requires different escaping rules. 2. Modern frameworks handle much of this automatically; don't disable those protections.
Scan file uploads for malware. Files should be moved to temporary storage, scanned, and only then moved to permanent storage if clean. Never trust that a file is what its extension claims to be.
Phase 4: Security Headers — The Silent Protectors
Properly configured HTTP headers block entire classes of attacks without changing a line of application code (1–4–9). Yet most sites get them wrong or skip them entirely.
A Content Security Policy (CSP) restricts which scripts can execute on your page. This is your best defense against cross-site scripting (XSS)-1–4. Start permissive, then tighten. In production, aim for script-src 'self' at minimum no inline scripts and no external domains you don't control.
HTTP Strict Transport Security (HSTS) enforces HTTPS for your entire domain. Set max-age to at least one year (31536000 seconds) and include the preload directive if you're ready to commit (1-3-4).
X-Frame-Options: DENY prevents clickjacking attacks by stopping your site from being embedded in frames 1–4. This is a one-line fix for an entire class of vulnerabilities.
X-Content-Type-Options: nosniff prevents MIME type sniffing, which can lead to cross-site scripting attacks [1–3–4]. It tells browsers to trust your Content-Type headers.
Referrer-Policy: strict-origin-when-cross-origin controls how much referrer information is shared when users navigate away from your site [1–4]. This is a privacy control that also prevents certain information leaks.
Phase 5: Secrets Management — Never Hardcode
Hardcoded secrets are the most common vulnerability in AI-generated code and many production applications-8. An audit of 5,600 AI-generated apps found that 1 in 4 had Stripe or OpenAI keys sitting in client-side JavaScript-8.
Never commit secrets to source control, and similar files belong iin it. If you find a secret in your Git history, rotate it immediately.⁸.
Use a secrets management solution. We have things like AWS Secrets Manager, Azure Key Vault, and HashiCorp Vault. These things are important because they keep our secrets safe when they are not being used. They also make sure that only the right people can get to these secrets, and they keep a record of who does what.
We need to keep our keys and secret keys in different places. It is okay to put our Stripe keys in the environment variables that start with NEXT_PUBLIC_... We have to keep our Stripe secret keys and the secrets we use to sign webhooks on the server side where it is safe. We should not let anyone get to our Stripe keys and webhook signing secrets except on the server.
Never put service role keys in frontend code. This is how Supabase users get compromised. The service role key bypasses row-level security entirely—it should only exist in trusted server environments⁸..
Phase 6: Dependencies — The Supply Chain
Modern applications are assemblies of third-party code. Each dependency is a potential attack vector. The OWASP Top 10 now includes "Vulnerable and Outdated Components" as a standalone category for good reason.
Scan dependencies before every build. Use tools like npm audit Snyk or OSV-Scanner to identify known vulnerabilities in your dependencies (7-8). Block deployments when critical CVEs are present.
Update promptly. Security patches are released for a reason. Delaying updates increases exposure. Have a process for monitoring and applying security updates to both direct and transitive dependencies.
You need to keep a list of all the software you are using; this is called a Software Bill of Materials. It is like a list that says what software you have and where you got it from. When someone finds out that a piece of software has a problem, you can look at your list. See if you are using that software.
Phase 7 is about watching what is happening with your software;
It is called logging and monitoring. If someone is trying to break into your system, you need to be able to see what they are doing. A lot of people do not do a good job of keeping track of what is happening with their software.
You should write down things that happen with your software. This includes when someone tries to log in, whether they are successful or not. It also includes when someone tries to do something they are not allowed to do or when someone puts in information. You should also write down who did the thing, where they were when it happened, and what they were trying to do. This way, if something bad happens, you can look back. See what went wrong.
You should log things like when someone logs in, when someone tries to do something they are not allowed to do, and when someone puts in information. A Software Bill of Materials is very important; it helps you keep track of all the software you are using.
Use structured logging. JSON logs with consistent field names are searchable, analyzable, and alertable-7. Plain text logs are noise.
Never log sensitive data. No passwords, no session tokens, no API keys, and no personally identifiable information (PII) in logs. This requires discipline—review what your logging library captures.
Monitor for anomalies. Set up alerts for unusual patterns: failed authentication spikes, authorization failure bursts, unexpected request volumes— 2. The goal is detection in hours or minutes, not days or weeks.
Phase 8: Deployment — The Final Gate
Before you hit deploy, run through this checklist-8:
HTTPS is enforced. All HTTP requests redirect to HTTPS. Test with curl -i http://yourapp.comit—you should see a 301 or 302 redirect to the HTTPS version.
No debug endpoints in production. Grep for... or any routes that shouldn't be accessible. Attackers scan for these constantly.
Error messages don't leak internals. Test 404, 500, and permission error pages. Do they reveal stack traces, file paths, or database schema details? If yes, fix it-3.
Source maps are not in production. Source maps make debugging easier — and also make reverse-engineering your code easier. Disable them in production builds.
Application monitoring is configured. Sentry, LogRocket, or similar tools should be enabled and configured to sanitize sensitive data before transmission.⁸.
The 30-Minute Pre-Launch Audit
The difference between an amateur and a professional isn't knowledge — it's process. A security professional runs a checklist before every launch, the same as a pilot does before every flight.⁸.
A 30-minute pre-launch audit should include:
- Verify security headers are present (5 minutes)
- Test API rate limiting (5 minutes)
- Check for client-side secrets (5 minutes)
- Validate RLS policies (5 minutes)
- Scan dependencies for critical CVEs (5 minutes)
- Review error handling (5 minutes)
If you cannot check every box, you are not ready to launch. Security debt from day one is expensive to pay down.
The professionals don't have secret knowledge. They have discipline. They check the boxes before every launch. They learn from the breaches they've seen — and the ones they've prevented.
That discipline starts with a checklist. Now you have one. Use it.
Thanks for reading. Mubashir