Case study · September 6, 2026
Case study: scanning a vibe-coded SaaS, from finding to fix
This is a composite walkthrough, not one named customer. The app described here — a small subscription tool built almost entirely with an AI coding assistant, live for about three months, roughly 400 users — stands in for the pattern we see over and over. Every finding, and every fix, is one our scanner reports in the real world. We have changed nothing about the technical detail and invented no results.
The starting point
The owner was not careless. The app worked, payments worked, sign-in worked. Nobody had ever asked whether the database was readable by strangers, because nothing in the build process asks that question. A Deep Scan of the live URL took under two minutes and returned eight findings: two critical, two high, two medium, two low.
The eight findings
Database access open to anonymous visitors
Why it matters: Two tables holding customer records had row level security switched off. Anyone who found the project's public API key — which ships in every page — could read the whole table.
The fix: Row level security enabled on both tables, with policies scoping every row to the signed-in owner, plus explicit grants for the authenticated role only.
A privileged server key shipped to the browser
Why it matters: A key intended for server-only use had been added with a browser-visible prefix, so it was bundled into the JavaScript the site sends visitors. That key bypasses all access rules.
The fix: Key removed from the client bundle, rotated, and moved behind a server function. The old key was invalidated so any copy already scraped is worthless.
No Content-Security-Policy
Why it matters: Without a CSP, any injected script — from a compromised dependency, a user-supplied string, or a browser extension — runs with full access to the page and its session.
The fix: A policy added starting in report-only mode for a week, then enforced once the reports were clean.
Session cookie missing Secure and SameSite
Why it matters: A session cookie without those attributes can travel over plain HTTP and be attached to cross-site requests, which is the ingredient for session hijacking and CSRF.
The fix: Cookie reissued with Secure, HttpOnly and SameSite=Lax, and the host-prefixed name.
Sourcemaps published in production
Why it matters: Sourcemaps hand an attacker your original, commented source — including internal endpoint names and comments describing what is not yet validated.
The fix: Production sourcemaps disabled in the build config; the existing .map files removed from hosting.
Admin route protected only in the browser
Why it matters: The admin page hid itself when the visitor was not an admin, but the data it loaded had no server-side role check. Calling the endpoint directly returned everything.
The fix: Role verified on the server inside the data function before any query runs, using a role table rather than a flag on the user profile.
Missing HSTS and Referrer-Policy
Why it matters: Small headers with real value: one forces HTTPS on repeat visits, the other stops full URLs (often containing IDs or tokens) leaking to third parties.
The fix: Both headers added at the hosting layer — a two-line change.
Verbose error responses
Why it matters: Stack traces and database error text were returned to the browser, telling an attacker your table names, column names and library versions.
The fix: Generic messages returned to clients; the detail kept in server logs only.
How the fixes happened
Each finding came with a downloadable prompt describing the problem, the file or endpoint, and the change required. Those prompts went straight into the same AI assistant that built the app. The two critical items — database access and the leaked server key — were done first and took about an hour together, including rotating the key. The headers and cookie attributes were configuration changes measured in minutes. The admin route was the fiddliest, because it meant moving a decision from the browser to the server rather than adding a line.
The re-scan
A second scan the following day confirmed the critical and high findings were gone. The CSP stayed listed as a medium finding for the week it ran in report-only mode, which is correct — a policy that only reports does not yet block anything. After it was enforced, that finding cleared too. What is left on a healthy site is usually a short tail of low findings you accept deliberately, and being able to mark those as ignored so they stop resurfacing is part of the workflow.
What to take from this
- The dangerous findings were both access-control problems, not exotic exploits. That is typical.
- Nothing here required a security specialist. It required knowing the list of things to check.
- Fixing headers and cookies is cheap. Do those the day you launch, not the day after an incident.
- Re-scan after fixing. A fix you never verified is a belief, not a result.
Run the same scan on your own site
The free Lite scan needs no signup and takes seconds. You will see your score and how many issues are waiting.
Scan my site free