Skip to content
AI Build Safety

What Security Checks Should You Run on a Vibe-Coded Website?

In this article

  1. Why a working site is not automatically a safe site
  2. Start with access control, because that is where small apps often leak
  3. Check login like someone who is trying to bypass it
  4. Check permissions and ownership on every action
  5. Check forms for unsafe input and unsafe output
  6. Check database queries before trusting any URL or form value
  7. Check file uploads twice, or remove them until you need them
  8. Check errors and debug mode before production
  9. Check API, webhook, and automation endpoints
  10. Check CSRF on actions that change things
  11. Check secrets, HTTPS, backups, and rollback
  12. A practical vibe-coded website security checklist
  13. How to use AI to help with the checks
  14. When to get help from a real security person
  15. The takeaway

Question: What security checks should you run on a vibe-coded website?

Start with the places where a working demo can still hurt you: login, permissions, user data, forms, database queries, uploads, API endpoints, error handling, backups, HTTPS, and secrets. Ask AI to review those areas, but test the results yourself before putting the site online.

Why a working site is not automatically a safe site

Vibe coding can get you to a working website surprisingly fast. The homepage loads. The login form accepts a password. The dashboard appears. The database saves a record. The AI assistant says the code is ready.

That is useful. It is also not the same as safe.

The dangerous parts of a small web app are often underneath the happy path. The happy path is what happens when the right person clicks the right button with the right data. Security lives in the unhappy paths: the wrong user, the wrong record ID, the wrong payload, the direct URL, the missing permission check, the form field that accepts more than it should, the upload that was meant to be an image but arrives as something else.

That is why vibe-coded websites need a security pass before they go online. Not because vibe coders are stupid. Not because AI tools are useless. The risk is simpler than that: AI will often build the thing you asked for, and most people ask for “make it work” before they ask for “show me how this can break.”

If the site is only a private toy on your laptop, the stakes are low. If it has real users, logins, private dashboards, payments, uploads, customer records, or anything that writes to a database, the stakes change. You need to slow down.

This fits the same pattern as the safer workflow in The Safer AI Coding Workflow I’m Using to Build Terralog.online. AI can help you move faster, but the useful version still has review points.

Start with access control, because that is where small apps often leak

Access control is the boring-looking security layer that decides who can do what. It is also one of the most common places for real damage.

OWASP’s current Top 10 lists broken access control as the first risk area, and the examples are exactly the kind of things small vibe-coded apps can accidentally ship: users acting outside their intended permissions, changing IDs in URLs, viewing or editing someone else’s records, APIs with missing access checks, and admin areas that normal users can reach.

The small-app version is easy to picture.

You have a URL like this:

/app/projects/edit.php?id=42

What happens if user A changes 42 to 43?

The app should not just load record 43 because the URL asked for it. It should check that the user is logged in, that the record exists, that the current user owns that record or has permission to edit it, and that the check happens on the server. JavaScript hiding a button is not enough. Hiding a link in the menu is not access control. If the page exists, someone can try to load it directly.

Every read, edit, delete, export, and download action needs an ownership check.

That sentence is worth repeating in your own project notes. A dashboard list needs it. An edit form needs it. A file download needs it. An export button needs it. An API endpoint needs it. The AI may have protected the page you were looking at and missed the second route that does the actual save.

Check login like someone who is trying to bypass it

Authentication is not just “can I log in?” It is the whole set of decisions around proving identity and keeping that identity attached to the right session.

For a vibe-coded website, I would check the basics first:

  • Are passwords hashed, not stored as plain text?
  • Can users log out properly?
  • Does logout actually invalidate the session on the server?
  • Can a logged-out user load private dashboard URLs directly?
  • Are admin-only pages checking a real role or capability?
  • Can a normal user guess an admin URL and see anything useful?
  • If password reset exists, is it token-based and time-limited?
  • Are session cookies configured sensibly for production?

You do not need to become a full-time security engineer to run those checks. You do need to stop assuming that a working login form means the private parts are protected.

Try this manually: log out, paste a dashboard URL directly into the address bar, and see what happens. Then log in as a normal user and try the admin URL. Then try an edit URL for a record that belongs to a different account.

If the app trusts the browser too much, you will find out quickly.

Check permissions and ownership on every action

Permissions are where a lot of generated apps look fine until you test the wrong user.

The app may show the correct records in the dashboard, but the save endpoint may still accept any record ID. The UI may hide the Delete button, but the delete URL may still work if someone calls it directly. The export screen may show your own data, but the export handler may trust a hidden form field.

Do not trust hidden fields. Do not trust query string values. Do not trust the browser to tell the server who owns a record.

The server has to make the decision. It should know the current user from the session, load the record, and check whether that user is allowed to view, edit, delete, export, or download it.

This is a good place to use AI carefully. Ask it:

Review this feature for permission and ownership problems. Focus only on whether a logged-in user can access or modify records they do not own. Do not rewrite the whole file. Explain the risks first, then suggest minimal fixes.

That is a much better request than “make this secure.” It gives the AI a narrow target and gives you something you can test.

Check forms for unsafe input and unsafe output

Forms are where users talk to your app. That makes them useful, and it also makes them dangerous.

The simplest check is this: if a user submits text, and that text later appears on a page, does the browser treat it as text or as code?

That is the heart of cross-site scripting, often shortened to XSS. The practical version is not complicated: someone puts script-like content into a name, comment, title, note, profile field, uploaded filename, or support message, and later the app displays it in a way the browser runs instead of showing harmless text.

Saving unsafe text is not always the problem. Displaying it unsafely later is where the damage happens.

OWASP’s XSS prevention guidance is built around output encoding: untrusted input should be converted into a safe form before it is displayed in HTML, attributes, JavaScript, CSS, or URLs. You do not need the full theory to understand the habit. Treat user-submitted content as untrusted when you show it back on the page.

For a vibe-coded site, check:

  • Can someone paste a script-like test into a name, note, comment, title, profile, or message field?
  • Does the page show it as harmless text?
  • Does it behave differently inside an HTML attribute?
  • Does the app allow rich text, and if so, is it sanitized with a real library?
  • Are uploaded filenames displayed safely?
  • Are validation errors echoing raw user input?

If you are using PHP, WordPress, Laravel, Rails, Django, React, Vue, or anything else, the exact escaping tools differ. The principle does not. Escape output in the right context. Do not assume that because input was saved successfully, it is safe to display everywhere.

Check database queries before trusting any URL or form value

SQL injection is one of those topics that sounds more dramatic than the day-to-day fix usually is. The practical rule is simple: do not build SQL by gluing user input into query strings.

Use prepared statements or the safe query tools provided by your framework. Validate IDs as integers. Treat URL values, hidden form values, and request payloads as untrusted.

OWASP’s SQL injection guidance puts prepared statements with parameterized queries as the first main defense. That is the habit you want AI to follow. The database query should define the SQL structure, and user values should be passed as values, not pasted into the SQL as if they were trusted code.

For a small app, I would check:

  • Does any query combine raw request values directly into SQL?
  • Are IDs validated as integers before use?
  • Are search fields passed through parameterized queries?
  • Are hidden form fields trusted blindly?
  • Are admin filters using allow-lists for sort fields and directions?
  • Does the app expose database errors to users?

This is another good AI review target:

Check this form handling code for SQL injection risks. Look for direct SQL string building, untrusted URL values, hidden form values, and missing server-side validation. Explain the risky lines first. Suggest the smallest safe fix.

The important phrase is “explain the risky lines first.” You want understanding before patching.

Check file uploads twice, or remove them until you need them

File uploads are one of those features that seem simple until you realise you have given strangers a way to put files on your server.

If your vibe-coded site does not truly need uploads yet, remove the feature until it does. That is not cowardice. It is good scope control.

If uploads are needed, check:

  • Are file types restricted to an allow-list?
  • Is file size limited?
  • Are uploaded files renamed by the app?
  • Are filenames displayed safely?
  • Can someone upload a PHP file or another executable type?
  • Are private files protected from direct public access?
  • Are uploads stored outside executable paths where possible?
  • Are only authorized users allowed to upload?
  • Is there a CSRF check around upload forms?

OWASP’s file upload cheat sheet recommends allow-listing extensions, validating file types without trusting only the content-type header, changing filenames, setting size limits, controlling storage location, and making sure only authorized users can upload.

For an old-stack app, the scariest version is simple: a public upload folder that can execute server-side files. If the app lets someone upload a script and the server will run it, you have a real problem.

Keep uploads boring. Rename files. Limit them. Store them safely. Log what happened.

Check errors and debug mode before production

Vibe-coded apps often leak too much when something breaks.

During development, detailed errors are useful. You want file paths, line numbers, stack traces, SQL errors, and environment clues. In production, normal users should not see those details.

Users need a polite error. You need the details in a private log. Those are not the same thing.

Before putting the site online, check:

  • Is debug mode off in production?
  • Do errors reveal file paths?
  • Do database errors show table names or SQL queries?
  • Do API errors return stack traces?
  • Are logs stored somewhere private?
  • Do error pages reveal secret values, environment paths, or tokens?
  • Does the app fail safely when something is missing?

This is not just about hiding embarrassment. Error messages can teach attackers how your app is built. A missing table name, full server path, or raw SQL error can turn a guess into a map.

Check API, webhook, and automation endpoints

OSJ ends up talking a lot about workflows, because small useful apps often need to receive work from somewhere else: a form, a webhook, an automation tool, an AI step, a WordPress action, or an n8n workflow.

The same security rule applies: an endpoint is not safe just because it is obscure.

If your app has an API or webhook endpoint, check:

  • Does it require a token, API key, signature, or logged-in session?
  • Is that token checked on the server?
  • Are incoming payloads validated?
  • Are unexpected fields ignored or rejected?
  • Are rate limits needed?
  • Can the same request be replayed?
  • Does the endpoint log what happened?
  • Is there a receipt or review trail for important actions?

This is where Automation Receipts: A Readable Record for Workflow Runs fits. If an endpoint does real work, it should leave a record. Not a giant dashboard. Just enough to know what arrived, what ran, what changed, and what failed.

If the endpoint creates content, updates records, sends emails, charges money, or touches private data, it needs more than “the URL is hard to guess.”

Check CSRF on actions that change things

CSRF stands for cross-site request forgery. The plain-English version: can another website trick a logged-in user into submitting an action to your app?

You do not need to turn this section into a lecture. The practical check is this: if a form or endpoint changes something important, does it include a server-validated token or equivalent protection so the app knows the action came from your own form?

Sensitive actions include:

  • saving settings
  • changing email or password
  • deleting records
  • uploading files
  • inviting users
  • changing permissions
  • triggering exports
  • sending webhooks

Frameworks often have CSRF protection built in, but generated code may skip it, disable it, or only apply it to some routes. Ask AI to check that before launch.

Check secrets, HTTPS, backups, and rollback

Security is not only about attackers typing weird input into forms. It is also about the normal operational stuff that gets forgotten when a prototype becomes a real site.

Check secrets:

  • Are API keys, database passwords, tokens, and private credentials outside Git?
  • Is the environment file excluded from commits?
  • Are old keys rotated if they were pasted into a prompt, screenshot, or repo?
  • Does the production server have only the secrets it needs?

Check HTTPS:

  • Does the site force HTTPS?
  • Are cookies marked secure where appropriate?
  • Are callback URLs and API endpoints using HTTPS?

Check backups:

  • Do backups exist?
  • Have you restored from one at least once?
  • Are backups stored somewhere safer than the same folder as the app?
  • Do backups include sensitive data that needs protection?

Check rollback:

  • If the deploy breaks, what is the plan?
  • Can you go back to the previous version?
  • Do you know which files changed?
  • Is the database migration reversible, or at least understood?

This is why I like pre-shipping checklists. SaaS Pre-Shipping Checklist I Run Before Letting Real Users In is aimed at the broader “before real users” moment, but the same habit applies here. The point is not to create ceremony. The point is to catch the quiet risks before users do.

A practical vibe-coded website security checklist

Before putting the site online, check these in plain language:

  • Logged-out users cannot access private pages directly.
  • Normal users cannot access admin pages.
  • Every dashboard action checks the current user’s permission.
  • Users cannot view, edit, delete, export, or download another user’s records.
  • Passwords are hashed, not stored as plain text.
  • Login, logout, and session handling work properly.
  • Forms validate input on the server, not only in the browser.
  • User-submitted text is escaped when displayed.
  • Basic XSS tests render harmlessly as text.
  • Database queries use prepared statements or the framework’s safe query tools.
  • URL IDs and hidden form values are not trusted blindly.
  • File uploads are restricted, renamed, and safely stored.
  • Debug mode is off in production.
  • Error messages do not reveal paths, SQL, secrets, or stack traces.
  • API and webhook endpoints require authentication, tokens, or signatures where needed.
  • Sensitive actions use CSRF protection.
  • Backups exist and have been tested at least once.
  • The site has HTTPS enabled.
  • Secrets, API keys, and database passwords are not committed to Git.
  • There is a simple rollback plan if the deploy goes wrong.

That is not a complete professional security audit. It is a practical first pass for a small site that was built fast and now needs to stop pretending “it works” means “it is ready.”

How to use AI to help with the checks

AI can absolutely help with this. The trick is to ask it specific review questions instead of tossing the whole project at it and asking for security.

Use prompts like:

Review this PHP file for authentication and permission issues. Focus only on whether a logged-in user can access or modify records they do not own. Do not rewrite the whole file. Explain the risks first, then suggest minimal fixes.

Or:

Check this form handling code for XSS and SQL injection risks. Look for unsafe output, unescaped user content, direct SQL string building, and missing server-side validation. Explain the risky parts before suggesting changes.

Or:

Act as a security reviewer for this small web app. Create a checklist of manual tests I should run before deploying it. Focus on login, permissions, forms, file uploads, API endpoints, debug output, backups, HTTPS, and secrets.

Those prompts are better because they create inspection before modification. They also keep the AI from trying to redesign the whole app while you are just trying to find the risky parts.

This is the same debugging lesson from Make the Bug Smaller Before You Ask AI to Fix It, just applied to security. Make the question smaller. Make the risk visible. Then patch carefully.

When to get help from a real security person

Some projects need more than a checklist.

If your app handles payments, health data, legal data, private customer records, business-critical workflows, file uploads from strangers, public user accounts, or anything regulated, get someone qualified to review it before you rely on it.

That does not make vibe coding bad. It just means the risk is no longer a solo learning exercise. A professional review can find things your prompt will miss, especially in authentication, authorization, session handling, deployment, logging, and business logic.

The sensible version is not “never vibe code real things.” It is “know when the risk has outgrown your current review process.”

The takeaway

Vibe coding is fine for building small useful things, but the moment real users, real data, logins, uploads, private dashboards, automation endpoints, or payments are involved, you have to slow down and check the dangerous parts.

AI can help with that too. It can inspect files, explain risks, suggest minimal fixes, and generate manual test lists. But it will not magically know what your app is allowed to expose, who owns which records, or what happens if a stranger tries the wrong URL.

A working site can still be fragile. The goal is not to panic. The goal is to make the fragile parts visible before they become public problems.

Join the conversation

Your email address will not be published. Required fields are marked *

↑ Top