Loading...

What you need before you launch an App

The full set of things worth having in place before you go live, grouped by what each one protects, with what breaks when it is missing. Some of it will not apply to your stack. The last two sections cover how to tell, and what order to work in.

Launch guides stop at the parts every app shares, and the items that cost you real money sit outside them. This is the fuller list, around eighty checks across secrets, access, the browser, abuse, payments, model spend, deployment, user data, the legal pages, the build, and the non-security items that sink a launch anyway. It ends with the two answers people give too easily, and the order to work through it all.

How to read this

Most launch advice is made for one type of app. In a different app, many of those points may not apply.

So this list is grouped by what each item protects. The second column is what goes wrong without it. Read that first. If the consequence cannot happen in your app, skip the row.

No security background needed. Unfamiliar terms are in the glossary on this page.

Secrets and configuration

A leaked key makes everything else on this page pointless. Aim for one copy of each secret, held by a secrets manager, so rotating it is one change.

CheckWhat happens without it
No key reaches the browser bundleAnyone opens dev tools and reads it.
No key in the repository or its historyIt stays readable in every clone, forever.
Keys come from a manager at run timeRotation means finding every copy, and you miss one.
Separate keys for development and productionA laptop leak becomes a production incident.
Anything already committed is rotated, not deletedThe old value still works.
Missing config stops the process in productionA blank setting falls back to the permissive default.

Who can call it, and whose record it is

Most data leaks happen for two reasons.

CheckWhat happens without it
Every private endpoint checks the callerAn unauthenticated request returns real data.
Ownership checked per record, not per routeA user changes an id in the URL and reads another account.
Admin routes check a role as well as a loginAny signed-up user reaches the admin surface.
The same check on write as on readThey cannot see the record but can still edit it.
Sessions expire, and rotate on privilege changeA stolen identifier stays useful for months.
Cookies set secure, httpOnly and sameSiteThe session is readable by script, or sent across sites.
Second factor on admin accountsOne reused password owns your system.
Logout is a POST and truly ends the sessionAny page can log your users out, and the old identifier still works.
Email changes confirmed at both addressesOne session becomes a permanent account takeover.
A recovery path that survives the login providerTheir OAuth outage locks every user out, including you.

Change the session ID after login to prevent session fixation. Do this whenever permissions change, not just at login.

If the database uses row-level security, it can handle ownership automatically. If access is handled in the API, you need to check ownership in every query.

Both work. The API approach is easier to get wrong.

Input, output and the browser

Client-side validation is only for convenience. It can be skipped easily. Always enforce important rules on the server too.

CheckWhat happens without it
Server-side validation of every inputYour client rules are decoration.
Fields the client should not set are ignoredA signup carries an admin role, or a checkout carries its own price.
Responses carry only what the UI showsThe fields you never render are still readable in the JSON.
Output escaping on anything a user typedStored content runs as script for every reader.
A content security policyOne injected script has the whole page.
CORS limited to your own originsAny site can call your API from a logged-in browser.
CSRF tokens on cookie-authenticated writesA link in an email acts as whoever clicks it.
Upload size and type limits, stored off your domainYour storage bill, or an executable served from your origin.
Redirect targets checked against an allowlistYour login flow forwards users to an attacker page.

Escaping prevents XSS. Your framework does it by default, except where you disable it. Search for those places and check that the content is safe.

Abuse and the cost that comes with it

This group does not protect data. It protects your money.

If it takes payments

This is the one place a quiet bug moves your money to someone else. All of it comes down to not trusting what arrives.

If it calls a language model

Model endpoints have the two worst properties together, a price per call and free-form text as input.

Where it runs

The app can be correct and the thing serving it still hands data to the wrong person.

Users and their data

These become bigger problems later. They are cheap to fix now but harder once you have real users.

The legal side, and the pages that go with it

Which law applies is decided by where your users are, not where you are. One signup from Germany or Bengaluru brings that country rules with it. A small user count exempts you from nothing.

Three regimes cover most of what a new app meets. They ask for similar things. They differ on one point, which direction consent runs in.

Brazil, Canada and Australia follow the same pattern with different names. Satisfy GDPR and you are close to all of them, which is why it is the cheapest baseline.

The pages to have before the first signup

Where the code and the policy disagree

This is an engineering summary of what these laws ask software to do, current as of September 2026. It is not legal advice. Thresholds and deadlines move, and anything with real revenue or health, financial or children data behind it is worth an hour with a lawyer.

The build and what it pulls in

Your supply chain is all the packages, images, and CI actions you use but didn't write. They can run with your build permissions.

CheckWhat happens without it
CI actions pinned to a commit, not a tagA tag gets moved and new code runs in your pipeline.
Lockfile committed, installs are cleanTwo builds of the same commit differ.
A vulnerability audit that fails closedA green tick meaning the scanner could not run.
Build secrets scoped to the job that needs themEvery step can read your deploy key.
Tests and lint block the mergeA gate everyone learns to ignore.
Source maps and debug endpoints off in productionYour unminified code and internal routes are public.

Not a security issue, but it can still kill the launch

People still need to reach your app, use it, and tell you when it breaks. That has its own list.

Not applicable, and probably fine

Two answers come too easily on a list like this.

The first is not applicable. Sometimes true, when your architecture covers the risk elsewhere. Social login only, and password rules govern nothing.

Mark an item not applicable only when you can name what replaces it. If you cannot point at where, it is a gap wearing a friendlier label.

The second is probably fine. That belongs to the items decided route by route rather than in one shared place. Usually two, the fields a client may set and the fields a response returns. Middleware you can read once is verified. Forty routes each deciding for themselves is not.

Closing that is a boring afternoon. List every route that writes data or returns a record, check them one at a time. The one or two that fail are never the ones you would have guessed.

The order to do it in

Trying to do everything at once is how the work gets dropped. Follow this order and stop whenever needed.

Two habits matter more than the list itself.

None of this is a certificate. It tells you which risks your architecture handles, which it moved elsewhere, and which one you simply have not done. Most apps have exactly one of the last kind, and it is rarely the one they expected.