← All guides

Securing a Node.js or Laravel app: the checks we run before launch

Custom applications get hacked through a different set of doors than WordPress: debug pages, leaked environment files, unpatched packages, missing rate limits. Here is the list we run through before any Node.js or Laravel app goes live.

16 September 2026, 3 min read. From our own pre-launch list, which exists because of a Laravel app we inherited with debug mode on in production.

Custom applications do not have the plugin problem WordPress has. They have their own problems, and they are less forgiving, because there is no ecosystem of security plugins to fall back on. Every hole is one someone on the project left open. This is the list we run before launch and again after any major change.

Configuration

Debug mode off in production. Laravel with APP_DEBUG=true shows a full stack trace, environment variables and database credentials to anyone who triggers an error. We have inherited a live app in exactly this state. In Node, the equivalent is error handlers that return stack traces, and NODE_ENV not set to production.

Secrets out of the code and out of reach. Environment files not committed to the repository, and not reachable over the web. A .env file at a public path has leaked credentials for a lot of applications. Check that the web server refuses to serve dotfiles.

HTTPS enforced, with the app aware it is behind a proxy so redirects and secure cookies work. Cookies set with HttpOnly, Secure and SameSite.

Security headers. Content security policy, frame options, content type options, referrer policy, HSTS. In Node the helmet package does this in one line. Laravel needs middleware or the web server.

Dependencies

Audit the packages. npm audit or composer audit, with the findings fixed rather than ignored. A production app with hundreds of dependencies has a new known vulnerability most months. Automate the check.

Pin and update the runtime. Node on a current LTS release, PHP on a supported version. An unsupported runtime undoes everything else.

Remove what is not used. Every package is attack surface and a maintenance cost.

Input and data

Validate everything at the boundary. Every request body, query string and upload validated against what you expect, with the rest rejected. Laravel’s form requests and validation rules, or a schema library like zod in Node.

Queries through the ORM or parameterised. No string-built SQL, ever. This is what stops injection, and it is easier than the alternative.

Uploads treated as hostile. Type checked by content not by name, size limited, stored outside the web root or in object storage, never executable, served with the right content type.

Output escaped. Templates escape by default in both ecosystems. The risk is the places someone turned escaping off to render HTML.

Authentication and access

Rate limiting on login, password reset, signup and any endpoint that costs money or sends mail. Laravel has throttling built in; Node needs a package or the edge.

Sessions and tokens that expire, rotate on login, and are invalidated on logout and password change.

Authorisation checked on every request, not only in the interface. The classic hole is an endpoint that returns any record by ID because the check was only in the front end. Test by changing IDs in requests while logged in as a different user.

Password hashing with bcrypt or argon2, and two-factor for administrator accounts.

CSRF protection on state-changing routes. Laravel ships it; make sure nobody excluded routes from it. In Node, a token approach or SameSite cookies with care.

Operations

Run as an unprivileged user, not root. Process manager that restarts on crash.

Logging that captures auth failures and errors, shipped somewhere off the server, without logging secrets or personal data.

Backups of the database on a schedule, tested by restoring.

A way to know when it is down and when errors spike.

The two we see most

Debug mode on, and an authorisation check that only existed in the interface. Both are one-line fixes, both are found by someone who is not the developer looking with fresh eyes. That is the point of running a list rather than trusting memory. Our scanner covers the outside layer for any site: headers, HTTPS, exposed versions. The inside layer is this list.

See where your own site stands.

The scanner checks the things this guide talks about, in about ten seconds, no signup.

Tell us about the site.

A straight answer and a fixed quote, usually the same day.