SERVER SECURITY GUIDE

Vibe Coding Security Checklist: Protect Your App and Server

Short answer: to protect a vibe-coded app, work through nine checks in order: keep secrets out of code, enforce access rules on the server and in the database, review dependencies, lock down SSH and the firewall, close public ports, limit abuse and spend, restrict what AI agents can touch, keep tested backups, and set up alerts. None of it needs a security background, and most items take minutes.

Vibe coding means describing what you want to an AI assistant and shipping the code it writes, often without reading every line. The speed is real, but an app that runs is not the same as an app that is safe. Use this page as a pre-launch checklist and run it again every month.

Quick win (15 minutes)

  • Search your repository and chat history for pasted API keys, then revoke any you find. See Step 1.
  • Log in as a second test user and try to open the first user's data by changing an ID in the URL or request. It must be refused.
  • Run sudo ss -tlnp on the server and confirm only SSH, HTTP and HTTPS listen on public addresses.
  • Set a spending limit and an alert on every paid API key your app uses.
  • Run one database backup and try to restore it into a scratch database.
Nine-step vibe coding security checklist: secrets, access, packages, server, ports, abuse limits, AI agents, backups and alerts
The nine checks in this guide, in the order to do them.

Why vibe-coded apps need their own checklist

An AI assistant is good at producing something that works in the demo. It does not know which parts of your app are public, which keys are secret or what your hosting provider leaves open by default. The failures that hurt are usually not clever attacks. They are ordinary gaps that automated scanners look for: a key committed to Git, a database table anyone can read, a port open to the internet.

The checklist has two halves. Steps 1 to 3 and 6 to 7 protect the app and apply wherever it runs. Steps 4 and 5 protect the server and apply if you rent a VPS. If you deploy to a managed platform, the provider handles most of Steps 4 and 5, but the rest is still yours. For a full server-level list, see the VPS security checklist.

Step 1: Keep secrets out of code and out of the browser

A secret is any value that proves your app is allowed to do something: an API key, a database password, a token. Anyone who gets it can act as your app, and on a paid API that can mean someone else running up your bill.

  • Store secrets in environment variables or a secrets manager, never in source files, prompts or screenshots. Assistants often paste a key straight into code to make an example work.
  • Add .env to .gitignore before the first commit. Check whether it ever slipped in with git log --all --oneline -- .env. Any output means it was committed at some point.
  • Know which keys may reach the browser. Everything shipped to the frontend is public. Publishable keys are designed for that. Secret keys are not: Supabase's documentation says the service role bypasses row-level security, so keep it server-side and never expose it to customers.
  • Turn on secret scanning. GitHub's push protection blocks a push that contains a hardcoded credential. Per GitHub's documentation it is on by default for users pushing to public repositories, while repository-level protection must be enabled by an administrator.
  • Rotate, do not just delete. If a key reached a repository, a chat or a log, removing it from the file does not un-leak it. Revoke it and issue a new one. The steps are in Exposed .env and .git files.
Values that may reach the browser, such as publishable keys, versus values that must stay on the server, such as secret keys and passwords
Publishable keys are designed to be public; secret keys and passwords never are.

Step 2: Check who can see and change what

Access control means every request is checked on the server, for that user, for that record. Hiding a button in the interface is not access control, because anyone can send the request without the button. The OWASP Top 10 treats broken access control as a core web application risk, and AI-written code can skip it without any visible error.

  • Run the two-user test. Create two accounts, log in as the second and request the first one's record by changing the ID. Expect a refusal, not the data.
  • Enable row-level security on every exposed table if you use Supabase or another Postgres API layer. Supabase's documentation warns that a table in an exposed schema without row-level security is readable and writable by any role with a grant on it. Then write policies and test them as a signed-out visitor.
  • Check admin routes on the server. An admin page needs a server-side role check on every call it makes, not just a hidden link.
  • Use a proven login system instead of a home-made one, and turn on two-factor authentication (for example TOTP) for admin accounts and for the hosting and Git accounts that control the app.
  • Rate limit login and password reset so a script cannot try thousands of passwords. The principle is explained under rate limiting and brute-force attacks.

Step 3: Review the code and every dependency

You do not have to read every line, but you should read the lines that touch money, logins, files and the database. Ask the assistant to explain each of those parts in plain words and to list what it assumes. If the explanation does not match what you wanted, the code is wrong or the prompt was.

  • Insist on parameterised queries. Never build a database query by joining strings that include user input.
  • Validate input and uploads on the server: size, type and where the file is stored.
  • Check that each package really exists and is the one you meant. A 2024 study by Spracklen and colleagues, accepted at USENIX Security 2025, generated 576,000 code samples with 16 models and found hallucinated package names in at least 5.2% of commercial-model output and 21.7% of open-source-model output. The authors warn that an attacker can register such a name and wait. Before installing, run npm view package-name or open the registry page and look at age, maintainers and repository.
  • Commit the lockfile and install from it in production (npm ci for npm), then run npm audit or your language's equivalent after every dependency change.
  • Turn off debug mode in production and remove test accounts, demo routes and verbose error pages that print stack traces.

Step 4: Lock down the server

A new VPS is on the public internet from the moment it boots, and automated login attempts usually find it quickly. These five settings close the common doors. Do them in this order and keep one working SSH session open until the last test passes, because a mistake here can lock you out (the recovery guide covers that case).

Want a second pair of eyes on your server?

A free, read-only check shows what is exposed on your server and what to fix first.

Get your free server check Talk to a security engineer

Step 5: Close what should not be public

Vibe-coded projects often run exactly as they did on the developer's laptop: a development server on port 3000, a database on its default port, a debug panel left on. Check what is actually listening:

sudo ss -tlnp
Example ss output: PostgreSQL on localhost, SSH and nginx public, a Node dev server and Redis wrongly open on all interfaces
Illustrative output: the two highlighted lines are the ones to fix.

Every line whose local address is 0.0.0.0 or [::] is reachable from outside unless the firewall blocks it.

  • Keep databases and caches private. PostgreSQL, MySQL, Redis and MongoDB should listen on 127.0.0.1 or a private network, not the public address. See exposed databases on a VPS.
  • Put a reverse proxy such as nginx in front of the app and serve only ports 80 and 443. Do not expose the framework's development server to the internet. Hardening steps: nginx security best practices.
  • Use HTTPS everywhere and add the basic security headers and HSTS. Certificates are free and renew automatically; see Let's Encrypt renewal and TLS/SSL.
  • Mind Docker. Container ports published with -p can bypass ufw rules, so bind private services to localhost (127.0.0.1:5432:5432 in a compose file) and never mount the Docker socket into an app container. Details: Docker host security.
  • Make sure .env and .git are not downloadable from your domain. Request https://your-domain/.env in a browser; it must not return the file.

Step 6: Limit abuse and surprise bills

Public endpoints that call a paid service, such as an AI model, an SMS provider or an email API, are an invitation: anyone can script requests and you pay for them.

  • Call paid APIs only from your server, behind a login, with a per-user quota.
  • Set hard spending limits and alerts at every provider, including your cloud account.
  • Rate limit the expensive routes. In nginx, define a zone in the http block and apply it to the location:
    limit_req_zone $binary_remote_addr zone=api:10m rate=10r/s;
    
    location /api/ {
        limit_req zone=api burst=20 nodelay;
    }
    See limit_req.
  • Put a CDN or proxy in front of the site to absorb floods. Background and options: DDoS protection for small business websites and DDoS attacks.

Step 7: Keep AI agents on a short leash

Coding agents can run commands, change files and touch databases. That is the point, and it is also the risk. In July 2025 heise reported that Replit's AI agent had wiped a production database during a code freeze, after the user said he had told it not to change anything. According to the report, the agent then claimed a rollback was impossible although a backup existed. The account rests largely on the user's own screenshots, and Replit's CEO said the company was rolling out an automatic split between development and production databases. The lesson does not depend on the details: an instruction in a prompt is not a permission boundary.

  • Separate development and production, with different databases and different credentials. The agent gets only the development ones.
  • Give the agent the smallest rights that work: a read-only database user where possible, no root, no blanket sudo.
  • Require approval for destructive actions: deletes, DROP, migrations, force pushes and anything that touches production.
  • Work on a branch and read the diff before merging, so every change is reviewable and reversible.
  • Assume a mistake will happen and make sure Step 8 would survive it.
Five-step safe AI coding agent workflow: own branch, development credentials, agent changes, human diff review, approval before deploy
Limits enforced by permissions still hold when the agent ignores an instruction.

Step 8: Back up the data and rehearse the restore

Git saves your code, not your users' data. A backup you have never restored is a hope, not a backup.

  • Follow the 3-2-1 rule: three copies, on two kinds of storage, one off-site. A provider snapshot in the same account counts as one copy, not three. Full guide: VPS backup strategy.
  • Dump the database on a schedule (for PostgreSQL, pg_dump) and copy the dump off the server.
  • Keep one copy that cannot be changed or deleted from the server, for example with object lock. This is also your defence against ransomware.
  • Restore into a scratch database every month and note how long it took and how much data was lost. Those two numbers are your RPO and RTO.
Backup rehearsal loop: dump the database, copy it off the server, restore to a scratch database, time it, fix gaps and repeat monthly
Run the loop monthly; the timings become your recovery numbers.

Step 9: Watch it and know what to do when it breaks

Small apps get compromised quietly. Without alerts you learn about it from a user, a bill or your hosting provider.

The whole checklist on one screen

  • No secrets in code, prompts or the browser; leaked keys rotated.
  • Spending limits and alerts on every paid API.
  • Two-user test passed; row-level security on; admin routes checked server-side.
  • Two-factor authentication on admin, hosting and Git accounts.
  • Money, login, file and database code read; parameterised queries.
  • Every dependency verified; lockfile committed; debug mode off.
  • SSH keys only, no root login, firewall default-deny, automatic updates.
  • Only ports 22, 80 and 443 public; databases on localhost; HTTPS and headers on.
  • Rate limits and a proxy in front of the app.
  • AI agents work on a branch with development credentials and need approval for destructive actions.
  • 3-2-1 backups, one immutable copy, restore tested this month.
  • Uptime and log alerts running; incident plan written.

Go deeper: one guide for each step

Prefer to tick items off as you go? Use the interactive checklist, which saves your progress in your browser and prints cleanly. Every part of this page has a longer guide, and the vibe coder security hub lists them all.

Frequently asked questions

Is vibe coding safe for production apps?

It can be, if a human verifies what the AI wrote. Vibe coding does not remove the need for access control, secret handling, patched servers and backups. Treat AI output like code from an unknown contractor: review the parts that touch logins, money and data, and test before launch.

What should I check first in a vibe-coded app?

Check secrets and access control first. A leaked key lets strangers act as your app or spend your money, and missing access rules let one user read another user's data. Neither needs hacking skill to exploit, which is why Steps 1 and 2 come first.

Can an AI assistant secure my app for me?

It can help find problems, but it wrote the code and shares the same blind spots, so verify its work with the two-user test, a dependency check and a scan of what the server exposes. Do not give it production credentials or the right to run destructive commands without approval.

What do I do if I pushed an API key to GitHub?

Revoke the key at the provider and issue a new one immediately, then update the app. Deleting the file or the commit is not enough, because the key may already have been copied. Afterwards check the provider's usage log for activity you do not recognise.

How often should I back up a small app?

Back up as often as the amount of data you can afford to lose. Many small apps start with a daily database dump copied off the server. Whatever the schedule, restore it into a test database regularly, because only a tested restore proves the backup works.

Do I need a firewall if my host already has one?

Yes, it is still worth having a firewall on the server. A provider firewall and a server firewall protect at different layers, and the server one keeps working if the provider rule is misconfigured or removed. Allow only SSH, HTTP and HTTPS.

Does this checklist apply on Vercel, Netlify or other managed platforms?

Mostly. The platform handles the server steps (SSH, firewall, patching), but secrets, access control, dependencies, spending limits, backups of your database and AI agent limits remain your responsibility. Run Steps 1 to 3, 6, 7 and 8 at least.

Not sure where your server stands?

Get a free, read-only security check, or talk to a security engineer about managed protection.

Get your free server check Talk to a security engineer