Web app security checklist: the gaps that get apps breached
Most breaches of small web apps aren't clever. They come from a route that doesn't check who is calling, a secret in the code, a query built from user input or a database left open. Here's what to check, where to look in the code, and what good looks like.
Last reviewed by the Forge team
What goes wrong
What it costs when this is missed
Critical
Broken access control
One user reading or changing another user's data. It's the top risk in the OWASP Top 10, and usually one missing line.
Critical
Leaked secrets
A key in the code, the browser or the git history lets anyone use your accounts, at your expense.
High
Injection
Queries or HTML built from user input let attackers read your database or run script in your users' browsers.
Medium
Known holes in packages
Outdated dependencies with published vulnerabilities are the easiest way in, and scanners find them automatically.
Common problems
What to look for in your code
Each one: why it hurts, and how to spot it in your own project.
01Routes and actions that don't check the caller
Every API route, server action and webhook is a public entry point, whether or not your UI links to it.
How to spot it: List every route and server action. For each one, find the line that checks the session and the user's permission.
Risky
"use server";
export async function deleteProject(id: string) {
await db.project.delete({ where: { id } });
}
Example findingIssuesHighConfirmed in codeAny signed-in user can delete any projectapp/actions/projects.ts:12await db.project.delete({ where: { id } });no owner check: the ID comes straight from the client
Questions
Isn't a security scanner enough?
Dependency scanners find known vulnerabilities in packages. They can't tell that your delete route forgets to check the owner. You need both: a dependency check, and a review of your own code's access rules.
Are environment variables safe?
On the server, yes. Variables exposed to the browser (NEXT_PUBLIC_, VITE_ and similar) are public: anyone can read them in the downloaded JavaScript.
What should I fix first?
Anything that lets one user read or change another user's data. Then leaked secrets (rotate them; git history keeps them). Then injection and unchecked webhooks.