Skip to content
GrowthVector.io

Vibe Coding Security: Secrets, Auth and Supabase RLS

Vibe coding security for a real app: what to lock down before launch

Updated

Vibe coding security means closing the gaps that a coding agent leaves open by default. This page is Step 6 of 12 in the Vibe Coding guide. You leave with a launch checklist for Bookly, a Supabase policy you can test, and rules for keeping secrets and agent permissions under control.

The running example is Bookly, a booking app for a small hair salon. Clients book a slot and pay a deposit, and the owner sees the day's bookings. This page locks Bookly down in four places: client data behind row level security, the payment secret key on the server, the payment webhook checked before a booking changes, and the agent's own database and tool access.

Supabase changed its Data API grants in 2026, so each table now needs a grant, row level security, and policies. The sections below give the dates, the policy patterns and tests that stop silent failures, and the agent and MCP risks that now sit next to your code.

Related guides: TDD & Testing, Architecture, Getting Started, Deployment & Ops.

Launch Checklist

Vibe coding security checklist before you launch Bookly

Run this list once before the first client books a slot. Each line points to the section that explains it. The tests that prove these checks hold are on the TDD page.

Every .env file is in .gitignore. Only a template with empty values is committed.
No secret uses a NEXT_PUBLIC_ or VITE_ prefix. Secrets stay in server environment variables.
Every table has a grant, row level security turned on, and policies. See the Supabase RLS section.
Bookly check: signed in as client A, you cannot read or change client B's booking.
Every route handler, server action and data query checks the session itself, not only middleware.
The payment secret key stays on the server. A Bookly booking changes to paid only after a signed webhook arrives.
Every input is validated on the server with a schema before it reaches the database.
Login, signup, password reset and AI calls have rate limits.
The coding agent uses read-only database access on a development project, with manual approval on.
TruffleHog scans the full git history and finds no live secret.
Spend limits and billing alerts are set for every AI and cloud provider.
Every key that was ever public is rotated, not only deleted.

Secrets & Keys

The Vibe Coding Security Crisis

28.65 million new hardcoded secrets reached public GitHub commits in 2025, up 34% from the year before. GitHub reported more than 39 million secrets leaked across GitHub in 2024. That counter is different, so do not compare the two figures. nearly 44% of AI-generated code fails Veracode's security tests. Wiz reported in September 2025 that 1 in 5 organizations building on these platforms are exposed to risk.

How Secrets Leak

  • Committed .env files: A missing .gitignore entry lets the real file reach the repository.
  • Client-side exposure: NEXT_PUBLIC_ and VITE_ prefixes bundle secrets into browser-visible JavaScript.
  • AI chat context: Pasting API keys into AI prompts can potentially leak them to third parties.
  • Hardcoded in source: AI often writes const API_KEY = "sk-..." directly into code.
  • Git history: git rm .env removes the file, but the key stays in commit history until you rewrite it. Rotate the key first.
  • MCP and editor config files: GitGuardian found 24,008 unique secrets in MCP-related config files on public GitHub. Of those, 2,117 were valid.

Real-World Cost

Minutes, not days

Bots find keys pushed to GitHub within minutes. The 2023 honeypot tests saw leaked keys used within 2 minutes (Orca), and first abuse within 1 minute (Comparitech). Deleting the commit does not help. Rotate the key.

LLMjacking: up to $46,000 per day

Attackers steal exposed API keys to run their own LLM workloads. You pay the bill. Sysdig's 2024 worst-case estimate was up to $46,000 per day.

The .env Setup (Do This First)

# .gitignore (MUST include these)

.env

.env.local

.env.production

.env*.local

# .env.example (commit this template)

DATABASE_URL=

STRIPE_SECRET_KEY=

OPENAI_API_KEY=

# Never commit actual values

Check required variables at startup

Validate required environment variables with a schema when the server starts. A missing secret then fails at startup, not on the first live request. The env var rules themselves are on the getting started page.

Secret Scanning Tools

TruffleHog

Detects over 800 secret types and tells you whether each one still works. Scans git history, not just current files. Licensed under AGPL-3.0.

Recommended

Gitleaks

Feature complete, so it gets security patches only. Its author now builds Betterleaks (MIT), which adds opt-in live checks with --validate. The pre-commit hook still works.

Feature complete

GitHub Secret Scanning

Secret Protection is free for public repositories, and push protection is on by default there. It blocks commits that contain known secret patterns. Private repositories pay per active committer. GitHub's example rate is $19 per active committer (USD).

Free for public repos

How to Rotate Leaked Keys

1

Revoke Immediately: Delete the key in the provider dashboard (AWS, OpenAI, Supabase). Every minute it stays live, bots can use it. Supabase revokes secret keys it finds in public GitHub repositories, but do not rely on that.

2

Rotate: Create a new key with the smallest scope. Update .env.local and the host's environment settings (Vercel or Railway).

3

Clean History: After the old key is dead, remove the file from git history with git filter-repo, as GitHub's guide describes. git rm is not enough. The workflow page covers the full cleanup.

4

Scan: Run TruffleHog against the full repo, history included, to find other live secrets.

API Key Rotation Schedule

A schedule this guide recommends. It is a practice, not a compliance rule.

Production Keys

90 days

Stripe, OpenAI, database credentials

Development Keys

6 months

Test API keys, staging DB passwords

Team Member Departure

Immediate

Rotate every key the departing member had access to

Suspected Compromise

Immediate

Revoke first, investigate second, generate new keys third

Blast Radius Containment

Limit damage when (not if) something goes wrong. Host settings and monitoring are covered on the deployment page.

OpenAI

Use prepaid credits and set hard limits at the organization and project level. When credits run out, the API returns a billing error. Prepaid credits expire after one year.

AWS

Set budget at $10. Alert at 80%. Use Service Control Policies to prevent launching expensive resources.

Stripe

Monitor dashboard daily for unusual charges and potential fraud patterns.

All Keys

Least privilege per environment. Dev keys should have minimal permissions. Never use production keys locally. Rotate every 90 days.

Auth, IDOR & Supabase RLS

Authentication vs. Authorization

Authentication is "Who are you?". Authorization is "What can you do?". AI often builds the login (Auth) and skips the permission check (Authorization). That gap leads to IDOR.

Auth Provider Comparison

ProviderFree TierPaidNotes
ClerkHobby: 50,000 MRU per appPro: $25/mo, or $20/mo billed annually. Extra MRUs $0.02/mo each (50,001 to 100,000)Drop-in UI components. Lower rates at higher volume
Supabase Auth50,000 MAU. Free projects pause after 1 week of inactivityPro: 100,000 MAU included, from $25/month. $0.00325 per MAU above thatIntegrated with the Supabase database and its RLS policies
NextAuth/Auth.jsFree (open source)Self-hostedNow maintained by the Better Auth team, which recommends Better Auth for new projects
LuciaFree (open source)Self-hostedDeprecated March 2025. Do not start new projects on it
Auth0Up to 25,000 MAU, $0/monthEssentials (B2C) from $35/monthEnterprise-grade. Expensive at scale

CVE-2025-29927: One Header Skipped Middleware Auth

The x-middleware-subrequest header let a request skip middleware-based auth checks. Vercel disclosed it on February 27, 2025, and rated it critical. Patches shipped in 12.3.5, 13.5.9, 14.2.25 and 15.2.3. Self-hosted next start and output: standalone builds were affected. Vercel, Netlify and Cloudflare Workers hosting were not.

Lesson: Verify auth in each route handler and server action, not only in middleware. Vercel's own advice: "We do not recommend Middleware to be the sole method of protecting routes."

More middleware bypasses in 2026

CVE-2026-44575 (published May 13, 2026) let requests skip middleware or proxy checks through .rsc and segment-prefetch URLs in the App Router. Fixed in 15.5.16 and 16.2.5. CVE-2026-64642 (published July 27, 2026) let crafted requests bypass middleware or proxy auth in App Router apps that use Turbopack with a single locale, in versions 16.0.0 to 16.2.10. Fixed in 16.2.11.

React2Shell: CVE-2025-55182 (December 2025)

An unsafe deserialization flaw in React Server Components allowed remote code execution, rated CVSS 10.0. Fixed in React 19.0.1, 19.1.2 and 19.2.1. Next.js fixed it in 15.0.5, 15.1.9, 15.2.6, 15.3.6, 15.4.8, 15.5.7 and 16.0.7. An AI app builder can pin an old framework version in a template, so check the lockfile.

IDOR (Insecure Direct Object Reference)

The server returns a record for an ID in the request without checking that the signed-in user owns it. AI often builds the login and leaves out this check.

Vulnerable

GET /api/bookings?id=124

Client A changes the ID to 124 and sees client B's booking in Bookly.

Secure

GET /api/me/bookings

The server reads the client from the session token. The request cannot name another client.

IDOR Test (30 Seconds)

  1. 1.Log in as User A. Open DevTools Network tab.
  2. 2.Find an API request that includes a user ID or resource ID.
  3. 3.Copy the URL. Change the ID to a different number.
  4. 4.Paste it in a new browser tab. If you see another user's data, your app has IDOR.
  5. 5.Repeat the test with PATCH and DELETE requests. A change to another user's record must fail.

Authorization Middleware Pattern

Wrap all protected API routes with a reusable auth check. Never rely on client-side checks alone.

Client-Side Only (Insecure)

// User can edit JS to bypass this!

if (user.role !== "admin")

  return <div>Access denied</div>;

Server-Side Middleware (Secure)

// Reusable auth wrapper

export function withAuth(handler) &lbrace;

  return async (req) => &lbrace;

    const session = await getSession();

    if (!session) return 401;

    req.user = session.user;

    return handler(req);

  &rbrace;;

&rbrace;

Common AI-generated auth mistakes: Missing RLS in Supabase, client-side only checks, no email verification, weak password requirements (accepts "123456"), API routes with no session check, and session tokens in localStorage (vulnerable to XSS). Middleware can redirect a visitor, but each route handler still checks the session, because middleware can be bypassed.

Supabase RLS policies for Bookly: write them, test them, avoid silent failures

Row level security (RLS) is the database's ownership check. For Bookly, a client reads only the bookings that belong to that client's account.

Supabase Data API grants: the change dated May 30 and October 30, 2026

  • New projects, from May 30, 2026: a new table in public is no longer granted to the Data API by default.
  • All existing projects, from October 30, 2026: the same change applies. Tables that already exist keep their grants.
  • Each table needs three things: a grant for the role, enable row level security, and policies.
  • A missing grant returns error 42501 (permission denied) before RLS runs. Do not "fix" that with grant all to anon. That reopens the table.

Bookly: lock bookings to their owner

-- Clients read only their own bookings

alter table public.bookings enable row level security;

grant select on public.bookings to authenticated;

create policy "Clients read own bookings"

  on public.bookings for select to authenticated

  using ((select auth.uid()) = client_id);

create index bookings_client_id_idx on public.bookings (client_id);

The grant lets the Data API reach the table. RLS and the policy decide which rows the client sees. Add insert, update or delete grants and policies only for the actions Bookly needs.

Common Mistakes

  • Enabling RLS with no policy. The publishable key then sees no rows, and the app looks broken.
  • Using the secret key (legacy name: service_role key) in frontend code. A secret key bypasses RLS when the request has no user access token.
  • Writing using (true), or to anon using (true). Every visitor then reaches every row the policy covers.
  • Creating tables in the SQL Editor or in migrations without enable row level security. Tables made in the Table Editor get RLS by default. Other tables do not.
  • Views. A view bypasses RLS by default. On Postgres 15 and later, set security_invoker = true.
  • Policies based on user_metadata. Users can edit it. Store authorization data in app_metadata.
  • An UPDATE with no matching SELECT policy. The update can match zero rows and return no error.

Silent failures look like missing data

With RLS on and no matching policy, a select returns an empty list and no error. Bookly's screen then shows no bookings, and the bug looks like missing data. Test every action as a signed-in client and as an anonymous visitor.

Quick RLS test: run it on every table

Run this from a terminal with no user login. Rows in the reply mean anonymous visitors can read them. A 42501 error is a safe result. Repeat it for every table, and send POST, PATCH and DELETE requests too. The Moltbook exposure included write access, so test writes as well.

curl "https://your-project.supabase.co/rest/v1/bookings" -H "apikey: YOUR_PUBLISHABLE_KEY"

Let Supabase check the project for you

Supabase's Security Advisors, built on the open-source linter Splinter, flag tables without RLS, loose policies and exposed sensitive columns. They email weekly summaries to organization owners, and the Supabase MCP server can read them. Storage files need policies on storage.objects. Realtime also respects RLS, so a subscription receives only the rows its policy allows.

Key names: publishable and secret keys

Publishable keys (sb_publishable_...) and secret keys (sb_secret_...) replace the legacy anon and service_role keys. Legacy keys are deprecated by the end of 2026. Creating a new key does not revoke the old one, so disable the legacy key in Settings > API Keys. Keep the secret key on the server. Give each backend component its own secret key, so one leak means one rotation. Wiz's wording: a publishable key is safe to expose "when RLS is properly configured", because it works as a project identifier.

Input Validation with Zod

Never trust the client. Validate everything on the server.

// Server-side validation schema

const UserSchema = z.object({

  email: z.email(),

  name: z.string().min(1).max(100),

  password: z.string()

    .min(8, "Password must be at least 8 characters")

    .regex(/[A-Z]/, "Needs uppercase")

    .regex(/[0-9]/, "Needs number"),

};

Using safeParse in API Routes

// Always use safeParse, never parse (which throws)

const result = UserSchema.safeParse(req.body);

if (!result.success) {}

  return res.status(400).json({errors: result.error.flatten()});

};

// result.data is now fully typed and validated

const user = result.data;

Common Zod Patterns

// URL validation

z.string().url()

// Enum values

z.enum(["free", "pro", "enterprise"])

// Optional with default

z.string().optional().default("user")

// Age range

z.number().int().min(13).max(120)

Validation is not an XSS fix

Stripping angle brackets with .transform() does not prevent XSS. React escapes text by default, so validate the shape and size of the data here, and handle HTML in the render step.

XSS Prevention

Risk comes from dangerouslySetInnerHTML and javascript: links. Keep user content out of both, and sanitize it if you must render HTML.

SQL Injection

Query builders and ORMs such as Drizzle, which Bookly uses, parameterize queries for you. Never concatenate user input into SQL strings.

Rate Limiting

Add rate limiting to login, signup, and password reset. Use @upstash/ratelimit with Redis.

SQL Injection: Bad vs. Good

// DANGEROUS: Raw SQL concatenation

const query = `SELECT * FROM users

  WHERE email = '${email}'`;

// Attacker input: ' OR '1'='1

// Returns ALL users!

// SAFE: Parameterized query

const query = `SELECT * FROM users

  WHERE email = $1`;

await db.query(query, [email]);

// SAFE: Drizzle (parameterized)

await db.select().from(clients)

  .where(eq(clients.email, email));

XSS Prevention in React

// DANGEROUS: Never do this

<div dangerouslySetInnerHTML={

  {__html: userInput}}

/>

// SAFE: If you must render HTML, sanitize first

import DOMPurify from 'dompurify';

<div dangerouslySetInnerHTML={

  {__html: DOMPurify.sanitize(userInput)}}

/>

React auto-escapes text content by default. XSS only becomes a risk when you use dangerouslySetInnerHTML or inject content via href="javascript:..." attributes.

CSRF note: State-changing requests need CSRF protection too. Check your framework's documentation for the defaults it ships before you rely on them.

File Upload Security

File uploads are a common attack vector. Never trust the file extension or client-side MIME type.

Client-Side Validation (Zod)

const FileSchema = z.object({

  file: z.instanceof(File)

    .refine(f => f.size <= 5_000_000,

      "Max file size is 5MB")

    .refine(f =>

      ["image/jpeg", "image/png"].includes(f.type),

      "Only JPEG and PNG allowed")

});

Server-Side Verification

// Verify MIME by reading file bytes

import {fileTypeFromBuffer}from 'file-type';

const type = await fileTypeFromBuffer(buffer);

if (!type || !ALLOWED.includes(type.mime))

  throw new Error("Invalid file type");

Scan uploads for malware, for example with ClamAV, before any other user can open them.

Server-Side Proxy Pattern

Never call external APIs directly from client-side code with exposed keys. Instead, create a server-side API route that makes the call. Your frontend calls your server route, which calls the external API with the secret key. The key never reaches the browser. This is the proper alternative to prefixing secrets with NEXT_PUBLIC_ just to make something work.

Payments: keep the secret key on the server and check the webhook

Bookly takes a deposit when a client books a slot. The payment provider sends a webhook when the payment settles, and that webhook decides the booking status.

Secret key stays on the server

The payment secret key lives in a server environment variable. It never appears in client code, a browser response, a log line, or a prompt pasted into an AI tool.

Verify the webhook before anything changes

Check the webhook signature on the raw request body, with the signing secret, before you change any data. Reject a request that fails the check. A webhook can arrive twice, so mark the booking paid once, keyed on the event ID.

Bookly's rule

A deposit moves a booking to paid only after the signed webhook arrives. The browser's success redirect changes nothing, because the visitor controls that page.

Owner refunds

The owner's refund goes through a server route with the same rules: the owner's session is checked, the secret key stays on the server, and the logs hold no card data.

Where the webhook URL is hosted, and how spend limits are set, is covered on the deployment page.

Agents, MCP & Prompt Injection

The coding agent is part of the attack surface

An agent that reads your repository, runs shell commands and holds database access can be steered by the text it reads. Bookly's agent reads booking notes, support tickets and issue titles. The OWASP Top 10 for Agentic Applications (2026) names the risks. The ten items below show where Bookly's agent is exposed.

OWASP Top 10 for Agentic Applications, applied to Bookly

Ten risk items, in OWASP's ASI numbering.

ASI01: Agent Goal Hijack

Text in a booking note or a support ticket changes what the agent tries to do.

ASI02: Tool Misuse and Exploitation

The agent calls a database or shell tool in a way you did not intend, such as a broad query.

ASI03: Identity and Privilege Abuse

The agent uses a credential with more rights than its task needs.

ASI04: Agentic Supply Chain Vulnerabilities

A package, MCP server or agent tool that you install carries bad code.

ASI05: Unexpected Code Execution

The agent runs code that it generated or fetched, on your machine or on the server.

ASI06: Memory and Context Poisoning

Bad text saved in the agent's memory or in a context file changes its later work.

ASI07: Insecure Inter-Agent Communication

One agent passes unchecked output to another agent, which then acts on it.

ASI08: Cascading Failures

One wrong step spreads through a chain of tool calls and agents.

ASI09: Human-Agent Trust Exploitation

A reviewer approves an action because the agent's explanation sounds right.

ASI10: Rogue Agents

An agent keeps acting outside its task after the task is over.

Prompt injection and the lethal trifecta

Prompt injection is the attack on an agent through text it reads. These design rules limit the damage.

Prompt injection

Supabase's MCP guidance calls prompt injection "the primary attack vector unique to LLMs". Hidden instructions in user content, such as a support ticket, can make an assistant run harmful queries.

The lethal trifecta

Simon Willison's term for three things together: access to private data, exposure to untrusted content, and a way to send data out. An agent with all three can be turned into a data-theft tool by one injected prompt.

The Rule of Two

Meta's rule: without human approval, let an agent have at most two of the three properties in the trifecta. For Bookly's agent, that means the agent never holds private data, untrusted input and an outbound channel at the same time without a person in the loop.

OWASP LLM Top 10 (2025)

For an app that calls an LLM, LLM01 Prompt Injection and LLM06 Excessive Agency matter most. The 2025 edition is the current one on OWASP's page. OWASP maps prompt injection to six of the ten agentic categories.

Supabase MCP server: the settings that limit the agent

The MCP server gives the agent database tools. Each setting below narrows what the agent can reach.

# Point the agent at one development project, read-only, with two tool groups

<your Supabase MCP server URL>?project_ref=<dev-project-ref>&read_only=true&features=database,docs

  • read_only=true runs queries as a read-only Postgres user.
  • project_ref=<id> scopes the server to one project and disables account-level tools.
  • features=database,docs limits which tool groups the agent can use.
  • Keep manual approval of tool calls on. A confirmation dialog is a guardrail, not a guarantee.
  • Use a database branch or a development project for agent work. Connect production only when the task needs production data.
  • Do not give the MCP server to your customers.

Tool permissions and repository trust

Give each agent the smallest set of rights, and keep secrets out of any folder an agent can read.

  • Scoped, short-lived credentials: Give each agent its own credential with the rights its task needs. Never give it your owner-level key.
  • No real secrets in the project folder: An agent that reads the folder reads the secrets in it too.
  • Unknown repositories: Do not open a repository you do not know in an agent. Read its project files first.
  • MCP servers: Read what an MCP server does before you install it, and pin its version.
  • Updates: Keep the agent and its extensions up to date.

Secure vibe coding: rules the agent follows before it writes code

Tell the agent these rules before the first task, and check each one in review. The CSA secure vibe coding guide makes the same point: ask for env vars, validation and auth explicitly.

  1. 1.Secrets come only from server environment variables. No secret appears in client code or in a committed config file.
  2. 2.Every input is validated on the server with a schema before it touches the database.
  3. 3.Every query checks that the signed-in user owns the row. Auth is checked in each handler, not only in middleware.
  4. 4.Rate limits cover login, signup, password reset and each AI call.
  5. 5.The agent lists each security check it added, so the reviewer can test each one.

Evidence, Breaches & OWASP

Compliance Quick Reference

Privacy law, cookie consent, open-source licenses and accessibility rules are covered on the legal page. This page covers the security controls that those rules assume you already have.

Academic Evidence on AI Code Security

Published studies show that AI assistance can produce less secure code and more confidence in that code.

Perry et al. (ACM CCS 2023)

Participants with an AI assistant wrote significantly less secure code. They were more likely to believe their code was secure than the group without AI.

Perry et al., arXiv 2211.03622

Pearce et al. (IEEE S&P 2022)

Of 1,689 programs generated with GitHub Copilot across 89 scenarios, about 40% were vulnerable.

1,689 programs

Veracode 2026 GenAI report (July 28, 2026)

Average security pass rate about 56%, virtually unchanged from last year's report. Python passed most often at 63%, and Java least often at 30%. Syntax passed at about 100%.

100+ models tracked

Copilot Code Review Study

Copilot's code review frequently fails to detect critical vulnerabilities such as SQL injection. It also misses XSS and insecure deserialization. Its feedback mostly targets low-severity issues.

arXiv 2509.13650

The Overconfidence Trap

In the Perry et al. study, the participants with AI access felt more sure that their code was secure, and their code was less secure. Plan for review and runtime tests. Confidence is not evidence.

The vibe coding security risks that caused real leaks, 2025 to 2026

Each case names the cause that its source reports.

Moltbook (disclosed January 31, 2026)

A vibe-coded social network for AI agents. A Supabase publishable key in client JavaScript and no RLS gave anyone read and write access. Exposed: about 1.5 million agent API tokens, about 35,000 email addresses and 4,060 private DM conversations, some with plaintext OpenAI keys. The key was not the bug. Missing RLS was. Wiz reports five fix rounds in about three hours, and each round exposed more tables. Lesson: test writes, and retest every table after each fix.

UpGuard: public Supabase tables (October 14, 2026)

From about 300,000 domains with signs of Supabase use, UpGuard found 16,326 databases with publicly readable tables. Over half showed signs of personal data. UpGuard calls it a configuration problem (grants and RLS), not a Supabase flaw, and it has not confirmed malicious access.

RedAccess: apps public by default (May 2026)

A scan of about 380,000 publicly reachable assets on Lovable, Base44, Replit and Netlify found about 5,000 (1.3%) that held sensitive corporate data, such as hospital summaries and internal finance data. Some apps were public by default. A missing login on an internal tool is a second leak class, after RLS.

Base44 authentication bypass (2025)

Wiz reported that the register and verify-otp endpoints were open. The non-secret app_id was enough to create a verified account on a private app and bypass SSO. Wix fixed it within 24 hours.

Lovable apps with weak RLS (CVE-2025-48757)

Researchers reported 170+ apps built with Lovable that had missing or weak RLS, which exposed user data.

Escape.tech: scanning 5,600 vibe-coded apps

Escape.tech scanned more than 5,600 publicly available vibe-coded apps and reported:

  • More than 2,000 vulnerabilities
  • 400+ exposed secrets
  • 175 instances of exposed personal data

OWASP Top 10:2025 Mapped to AI-Generated Code

Built on about 175,000 CVE-to-CWE records from NVD and over 2.8 million applications in the contributed data, mapped to 643 CWEs. Each item below shows how it appears in vibe-coded apps.

A01: Broken Access Control

AI often skips the ownership check, so IDOR appears. SSRF, which had its own category before, now sits inside A01.

A02: Security Misconfiguration

Default settings shipped to production, debug endpoints left on, and Supabase or Firebase deployed without security rules. The category rose from fifth place to second in the 2025 list.

A03: Software Supply Chain Failures

Expands the earlier "Vulnerable and Outdated Components" category to dependencies, build systems and distribution. AI can suggest packages that do not exist. Attackers register those invented names. In a 2025 USENIX Security study, commercial models hallucinated about 5.2% of package names and open-source models about 21.7%. A May 2026 study of five frontier models reported 4.62% to 6.10%. For Bookly, run npm audit before each release (or pip-audit on a Python project), check that every package the agent adds exists and is the one you meant, and turn on Dependabot alerts in the GitHub repository so a vulnerable dependency opens a pull request.

A04: Cryptographic Failures

Hardcoded JWT secrets such as "supersecretkey", weak hashing such as MD5 or SHA1, and missing encryption at rest.

A05: Injection

AI uses string concatenation instead of parameterized queries, which produces SQL injection. Use parameters or an ORM for every query.

A06: Insecure Design

No threat model, and designs that cover only the happy path. The AI satisfies the prompt without the wider security context.

A07: Authentication Failures

No rate limit on login, weak password rules, and JWT handling that accepts the "none" algorithm.

A08: Software or Data Integrity Failures

Webhooks accepted without a signature check, and no dependency integrity checks.

A09: Security Logging & Alerting Failures

No audit trail for logins, permission changes and admin actions. Or the opposite: passwords and tokens written to logs.

A10: Mishandling of Exceptional Conditions NEW in 2025

Errors that leak stack traces, fail open instead of closed, or skip try/catch around third-party calls. The category has 24 CWEs.

JWT Mistakes AI Consistently Makes

Eight recurring JWT mistakes in AI-generated code, and the fix for each.

1

Wrong Algorithm

AI generates HS256 (symmetric) when RS256 (asymmetric) is needed for distributed systems. HMAC is less secure here because verification doesn't require a private key.

2

Outdated JWT Library

Old JWT packages stop receiving fixes. Check the lockfile for old versions, and use a maintained library.

3

Hardcoded Secrets

A placeholder secret such as "supersecretkey" committed to source is a secret anyone can copy. Load the secret from the server environment, and use a different one per environment.

4

"none" Algorithm Not Blocked

AI code often doesn't validate the alg header claim. Attackers set alg: "none" to bypass signature verification entirely, creating unsigned tokens.

5

Missing Claims Validation

AI decodes tokens without verifying exp (expiration), iss (issuer), and aud (audience) claims. Expired or misrouted tokens are accepted.

6

Algorithm Confusion Attacks

AI code accepts both symmetric and asymmetric algorithms. Attackers exploit RS256 to HS256 confusion, using the public key as an HMAC secret to forge tokens.

7

Token in localStorage

AI stores JWT in localStorage, which any script on the page can read (XSS vulnerability). Tokens belong in httpOnly cookies that JavaScript can't access.

8

Missing Token Lifecycle

No refresh token rotation, no token revocation, no expiration dates. Once issued, tokens work forever, even after password changes or account compromise.

Secrets Management by the Numbers

GitGuardian's 2026 report, which covers 2025 data, and IBM's 2025 breach report. Leaks are growing.

28.65M

New hardcoded secrets in public GitHub commits (2025)

Up 34% year over year

1,275,105

AI-service secrets found in 2025

Up 81%

3.2%

Commits assisted by Claude Code that leaked secrets

Baseline across public GitHub commits: 1.5%

24,008

Unique secrets in MCP-related config files

2,117 of them valid

Above 64%

Credentials from 2022 still valid in the January 2026 retest

GitGuardian retest

$4.44M

Global average cost of a data breach, USD (IBM, 2025)

Down 9% from $4.88M in the 2024 report

Key pattern: AI-service keys are the fastest-growing leak class, and MCP config files are a new place where keys leak. Keys that leak stay valid for a long time, so rotate on any exposure.

Rate Limiting Tools and Thresholds

Add rate limits to every endpoint that accepts user input or costs money.

express-rate-limit

Free. It had 93,253,875 npm downloads in the week of October 22 to 28, 2026. A common choice for Node.js and Express apps.

Gotcha: Behind proxies (Heroku, AWS, Cloudflare), you must set app.set('trust proxy', 1) or the limiter becomes global, blocking everyone.

Free

@upstash/ratelimit

The SDK is free. Redis is billed at $0.20 per 100K commands, and the free tier includes 500K commands per month. Supports sliding window, fixed window, and token bucket algorithms.

Best choice for Next.js + Vercel serverless deployments.

Serverless

Cloudflare Rate Limiting

Rules per plan: Free 1, Pro 2, Business 5, Enterprise 100 (contract-dependent). Free and Pro count by IP only. Blocking happens at the edge, before requests reach your origin.

No code changes needed.

No Code
Recommended Thresholds
EndpointLimitScope
Login5 attempts / 15 minPer IP
Signup3 / hourPer IP
Password Reset3 / hourPer email
API Endpoints100 / minutePer user
File Uploads10 / hourPer user
Expensive Ops (AI calls)5 / minutePer user

Audit Workflows & Prompts

Multi-LLM Security Audit Approach

Different AI models miss different vulnerability types. Using one model for security review leaves blind spots.

Semgrep Study (September 2025)

Claude Code (v1.0.32, Sonnet 4) and Codex (v0.2.0, o4-mini) were tested on 11 Python apps. Claude found 22% of IDOR bugs (13 of 59) but 5% of SQL injection (2 of 38). Codex found 47% of path traversal bugs (8 of 17) and 0% of IDOR (0 of 5). The IDOR sample is small, and both models are older versions. Do not read this as a current ranking.

Security Pass Rates (Veracode 2026)

Veracode's July 2026 report puts the average security pass rate at about 56%. Newer models write correct code more often, but not safer code, so review stays mandatory for every model.

Recommended Security Review Prompt

"Review this code ONLY for security vulnerabilities. Assume a hostile internet environment. Check for: exposed secrets, missing auth, injection, XSS, IDOR, missing rate limiting, insecure defaults. For each finding, state the vulnerability type, the specific line(s), and the fix."

Practical Multi-Model Workflow
1

Generate code with your primary model (Claude, GPT, Cursor).

2

Run the security review prompt above with a different model than the one that wrote the code.

3

Combine findings from both models. Models have complementary blind spots, so the union of their findings is more comprehensive than either alone.

4

Layer static analysis (Semgrep, SonarQube) on top of AI review. Deterministic tools catch pattern-based vulnerabilities that all models miss.

Copy-Paste Security Audit Prompts

Three structured audit prompts. Run each with a different AI model than the one that wrote your code.

Copy this comprehensive 11-pass OWASP audit prompt and give it to an AI model. Covers reconnaissance, all OWASP 2025 categories, exploit chain analysis, and structured reporting.

You are a senior offensive security engineer with 15+ years of experience in application security, penetration testing, and red-teaming full-stack applications. You specialize in finding vulnerabilities that automated scanners miss: business logic flaws, chained exploits, and subtle authorization gaps. You are conducting a manual security audit of this repository. Assume an adversarial threat model: the attacker has unlimited time, full technical capability, access to all public documentation, and high motivation (financial, ideological, or competitive). They will chain low-severity issues into high-severity exploits. ═══════════════════════════════════════════════════════════════════ PHASE 0: RECONNAISSANCE (do this first, before any vulnerability analysis) ═══════════════════════════════════════════════════════════════════ Before looking for bugs, build a mental model of the application: 1. **Identify the stack**: Languages, frameworks, ORMs, auth libraries, cloud providers, CI/CD tools, package managers 2. **Map the attack surface**: All entry points, including HTTP routes/endpoints, GraphQL resolvers, WebSocket handlers, cron jobs, queue consumers, CLI commands, file upload handlers, webhook receivers, SSR pages 3. **Identify trust boundaries**: Where does user input first touch server-side code? Where do services communicate? Where does privilege escalation become possible? 4. **Map the data flow**: How does sensitive data (credentials, PII, tokens, payment info) move through the system? Where is it stored, transmitted, cached, logged? 5. **Identify auth architecture**: Session management, JWT implementation, OAuth flows, API key handling, service-to-service auth, RBAC/ABAC model Output this as a brief "Attack Surface Summary" before proceeding. ═══════════════════════════════════════════════════════════════════ PHASE 1: VULNERABILITY ANALYSIS (multi-pass, ordered by OWASP 2025 risk) ═══════════════════════════════════════════════════════════════════ Conduct the audit in the following order, mapping each finding to its OWASP 2025 category and CWE ID. Do NOT fabricate CWE IDs. If you are unsure, state "CWE-TBD" with your best description. ────────────────────────── PASS 1: ACCESS CONTROL & AUTHORIZATION [OWASP A01:2025] ────────────────────────── - Can users access, modify, or delete other users' resources? (IDOR) - Can users escalate privileges (horizontal or vertical)? - Are there missing authorization checks on any endpoint? - Are there inconsistencies between what the UI shows and what the API allows? - Can API parameters be tampered to bypass access controls (forced browsing, parameter pollution, mass assignment)? - Is there SSRF potential via user-controlled URLs? - Are admin/internal endpoints exposed or guessable? - Can JWT claims be tampered, or are tokens validated on every request? - Is the deny-by-default principle followed? ────────────────────────── PASS 2: SECURITY MISCONFIGURATION [OWASP A02:2025] ────────────────────────── - Default credentials, keys, or secrets in code, config, or env files? - Debug mode, verbose errors, or stack traces exposed in production? - CORS policy: is it wildcard or overly permissive? - Security headers missing (CSP, HSTS, X-Frame-Options, X-Content-Type)? - Unnecessary services, ports, or features enabled? - Cloud storage buckets or database instances publicly accessible? - Are TLS/SSL configurations current (no SSLv3, TLS 1.0/1.1)? - Are default framework configurations left unchanged? - Is there .env, .git, or config file exposure? ────────────────────────── PASS 3: SOFTWARE SUPPLY CHAIN [OWASP A03:2025] ────────────────────────── - Dependencies with known CVEs? - Pinned versions or floating/wildcard version ranges? - Lock file present and committed? (package-lock.json, yarn.lock, etc.) - Are install scripts in dependencies reviewed? - Build pipeline integrity: can a compromised dependency inject code? - Is SBOM (Software Bill of Materials) maintained? - Are there typosquatting risks in dependency names? - Is there dependency confusion potential (private vs public registries)? ────────────────────────── PASS 4: CRYPTOGRAPHIC FAILURES [OWASP A04:2025] ────────────────────────── - Weak hashing (MD5, SHA1, single-iteration SHA256 for passwords)? - Is bcrypt/scrypt/argon2 used with appropriate work factors? - Secrets, API keys, or credentials hardcoded or committed to VCS? - Are encryption keys properly rotated and managed? - Is data encrypted at rest and in transit? - Are random number generators cryptographically secure? - Certificate validation disabled anywhere? - JWT using "none" algorithm or weak signing? ────────────────────────── PASS 5: INJECTION [OWASP A05:2025] ────────────────────────── - SQL injection (raw queries, string concatenation, ORM bypass)? - NoSQL injection (MongoDB operator injection, $where, $regex)? - Command injection (exec, system, spawn, eval, child_process)? - LDAP injection, XPath injection, template injection (SSTI)? - Header injection (CRLF, Host header)? - Is input validated/sanitized at every trust boundary, not just the front end? - Are parameterized queries / prepared statements used universally? - Is there any use of eval(), innerHTML, dangerouslySetInnerHTML, or equivalent in any language? ────────────────────────── PASS 6: INSECURE DESIGN [OWASP A06:2025] ────────────────────────── - Business logic flaws: Can workflows be abused (e.g., apply coupon twice, skip payment step, manipulate quantity to negative)? - Race conditions: TOCTOU vulnerabilities in critical operations (double-spend, double-vote, simultaneous resource claims)? - State machine abuse: Can users force the application into unintended states by replaying, reordering, or skipping steps? - Are rate limits and anti-automation controls in place for auth, signup, password reset, OTP validation, API consumption? - Is there abuse potential in features like file upload, export, search, or batch operations (e.g., zip bombs, CSV injection, ReDoS via search)? - Are there missing or bypassable CAPTCHA or bot protections? - Is there a threat model documented? ────────────────────────── PASS 7: AUTHENTICATION FAILURES [OWASP A07:2025] ────────────────────────── - Credential stuffing / brute force protection? - Password policy enforcement (length, complexity, breach lists)? - Session fixation, session hijacking vectors? - Secure cookie flags (HttpOnly, Secure, SameSite)? - Token expiry and refresh token rotation? - Multi-factor authentication bypass potential? - Password reset flow (token expiry, token reuse, user enumeration)? - Account lockout DoS potential? - OAuth/OIDC implementation flaws (state parameter, redirect URI validation, token leakage)? ────────────────────────── PASS 8: DATA INTEGRITY FAILURES [OWASP A08:2025] ────────────────────────── - Deserialization of untrusted data? - Auto-update mechanisms without signature verification? - CI/CD pipeline integrity (can a compromised step inject code)? - Are webhooks verified (signature validation)? - Can users modify serialized objects or state (cookies, hidden fields, local storage) to bypass server-side logic? ────────────────────────── PASS 9: LOGGING & ALERTING FAILURES [OWASP A09:2025] ────────────────────────── - Are authentication events (login, failure, lockout) logged? - Are authorization failures logged? - Are logs tamper-resistant and centralized? - Are sensitive values (passwords, tokens, PII) leaked into logs? - Is there log injection potential (user input in logs)? - Are alerts configured for anomalous patterns? - Is there sufficient audit trail for compliance (who did what, when)? ────────────────────────── PASS 10: EXCEPTIONAL CONDITION HANDLING [OWASP A10:2025] ────────────────────────── - Do errors fail open (granting access) instead of fail closed? - Are exceptions caught too broadly, hiding security-relevant errors? - Can error messages be used for enumeration (user exists, wrong password, etc.)? - Are timeouts and resource limits enforced (preventing DoS via infinite loops, recursive calls, memory exhaustion)? - Are null/undefined states handled, or do they cause crashes that bypass security checks? - Are edge cases in numeric handling addressed (integer overflow, floating point precision in financial calculations)? ────────────────────────── PASS 11: CROSS-CUTTING CONCERNS ────────────────────────── - XSS (stored, reflected, DOM-based): Is output encoding applied contextually (HTML, JS, URL, CSS contexts)? - CSRF: Are anti-CSRF tokens used for state-changing operations? Is SameSite cookie attribute set? - File uploads: Type validation (magic bytes, not just extension), storage location, execution prevention, size limits? - API security: Is there a versioning strategy? Are deprecated endpoints removed? Is there request size limiting? - WebSocket security: Origin validation? Authentication on connection? Message validation? - Sensitive data in URLs, referrer headers, or browser history? - Caching of sensitive responses (Cache-Control, Pragma headers)? ═══════════════════════════════════════════════════════════════════ PHASE 2: EXPLOIT CHAIN ANALYSIS ═══════════════════════════════════════════════════════════════════ After individual findings, identify how low/medium severity issues can be CHAINED together to create high/critical impact exploits. Example chains to look for: - Information disclosure + IDOR = full account takeover - SSRF + cloud metadata = credential theft + lateral movement - XSS + CSRF + missing re-auth = privilege escalation - Error message enumeration + brute force + weak password policy = breach - Race condition + missing idempotency = financial loss ═══════════════════════════════════════════════════════════════════ PHASE 3: OUTPUT FORMAT ═══════════════════════════════════════════════════════════════════ For EACH finding, use this exact structure: ### [FINDING-ID] Title - **Severity**: CRITICAL | HIGH | MEDIUM | LOW | INFORMATIONAL - **Confidence**: HIGH | MEDIUM | LOW (HIGH = I can see the vulnerable code and the exploit path is clear. MEDIUM = Strong indicators but I'd need runtime verification. LOW = Potential issue based on patterns, needs manual confirmation.) - **OWASP 2025**: A01-A10 category - **CWE**: CWE-XXX, Name (or CWE-TBD if uncertain) - **Location**: file(s), function(s), line(s) - **Description**: What the vulnerability is, in plain language. - **Attack Scenario**: Step-by-step, how an attacker would exploit this. Be specific. Show the curl command, the malicious payload, or the sequence of actions. - **Impact**: What the attacker gains. Data breach? Account takeover? RCE? Financial loss? Quantify business impact where possible. - **Remediation**: Specific fix with code example in the same language/ framework as the codebase. Not generic advice, but a drop-in fix or clear refactor path. Include both the immediate fix and any defense-in-depth recommendations. - **References**: Relevant CWE/CVE links, framework documentation, or security advisories. ═══════════════════════════════════════════════════════════════════ PHASE 4: EXECUTIVE SUMMARY ═══════════════════════════════════════════════════════════════════ After all findings, provide: 1. **Risk Overview**: Total findings by severity (CRITICAL: X, HIGH: X, MEDIUM: X, LOW: X, INFO: X) 2. **Top 3 Risks**: The most dangerous findings or exploit chains, written for a non-technical stakeholder 3. **Quick Wins**: Fixes that take <1 hour and eliminate HIGH/CRITICAL risk 4. **Systemic Patterns**: Recurring weaknesses that suggest missing security practices (e.g., "no input validation middleware anywhere" or "authorization checks are ad-hoc, not centralized") 5. **Recommended Security Investments**: Architectural changes, tooling, or processes that would structurally reduce risk (e.g., "adopt a centralized authz library", "add SAST to CI/CD", "implement CSP headers globally") ═══════════════════════════════════════════════════════════════════ RULES OF ENGAGEMENT ═══════════════════════════════════════════════════════════════════ - Be paranoid. Assume everything is an attack vector. - Do NOT report theoretical issues without evidence in the code. - Do NOT hallucinate file paths, function names, or CWE numbers. - If you are uncertain, say so and mark confidence as LOW. - Prioritize findings by real-world exploitability, not textbook risk. - Look for what automated scanners miss: logic flaws, chained exploits, design-level weaknesses, and implicit trust assumptions. - Think like an attacker, report like a consultant.

Deep dive on auth. The most attacked surface in any web application.

You are a senior authentication security specialist with 15+ years of experience in identity and access management, penetration testing auth systems, and red-teaming SSO/OAuth/JWT implementations. You have deep expertise in credential attacks, session hijacking, token forgery, MFA bypass, and account takeover chains. You are conducting an exhaustive security audit of the authentication implementation in: `/folder-name` Examine EVERY file involved in: user registration, login, logout, session management, password reset, email verification, MFA/2FA, OAuth/social login, API key management, and any admin/impersonation flows. Threat model: Assume an attacker with: - Unlimited time, technical skill, and access to tools like Burp Suite, hashcat, jwt_tool, and Evilginx - Knowledge of your exact tech stack, auth library, and version - A valid account on the platform (for authenticated attacks) - The ability to intercept network traffic (coffee shop WiFi scenario) - Motivation for full account takeover of any user, including admins ═══════════════════════════════════════════════════════════════════ PHASE 0: AUTHENTICATION ARCHITECTURE RECONNAISSANCE ═══════════════════════════════════════════════════════════════════ Before analyzing vulnerabilities, map the authentication system: 1. Auth stack identification: Auth library/provider (NextAuth, Passport, Devise, Supabase Auth, Firebase Auth, Clerk, Auth0, custom), session strategy (JWT vs server-side sessions vs hybrid), database for credentials/sessions 2. Authentication flow mapping: Every path to authenticated state: email/password, OAuth providers, magic links, passkeys/WebAuthn, API keys, service tokens, admin impersonation 3. Session lifecycle: How sessions are created, stored, validated, refreshed, and destroyed. Where are tokens stored client-side? (cookies, localStorage, sessionStorage, memory) 4. Trust boundary mapping: Where does the auth middleware run? Which routes/endpoints are protected vs public? Is there a centralized auth guard or per-route checking? 5. Credential storage: Where are passwords hashed? Where are OAuth tokens stored? Where are API keys/secrets kept? Where are session records persisted? 6. Recovery flows: Password reset, email change, account recovery, MFA recovery/backup codes: every path that grants access without the primary credential Output this as an "Authentication Architecture Summary" before proceeding. ═══════════════════════════════════════════════════════════════════ PHASE 1: VULNERABILITY ANALYSIS (12 audit passes) ═══════════════════════════════════════════════════════════════════ PASS 1: PASSWORD STORAGE & POLICY [CWE-916, CWE-521] - Hashing Algorithm: Acceptable: bcrypt (cost >=12), scrypt, Argon2id. REJECT: MD5, SHA-1, SHA-256 (even with salt), single-iteration PBKDF2. Verify unique per-password salt, server-side hashing, no plaintext/base64 storage or logging. - Password Policy: Min 8 chars, reasonable max (128), breached password list check (top 10K minimum), no overly restrictive composition rules per NIST 800-63B. - Credential Hygiene: No passwords in logs/errors/stack traces, HTTPS only with HSTS, all sessions invalidated on password change. PASS 2: SESSION & TOKEN MANAGEMENT [CWE-384, CWE-613, CWE-539] - JWT Security: Algorithm explicitly set in verification (not just signing), "none" algorithm rejected, algorithm confusion attacks (RS256→HS256) prevented, kid/jku/jwk/x5u header injection checked. Secret >= 256 bits entropy, not hardcoded, not shared across environments. All claims validated (exp, iss, aud, nbf). Access tokens 5-15 min, refresh tokens 7-30 days with rotation and reuse detection. - Cookie Security: HttpOnly, Secure, SameSite=Strict/Lax, minimal domain scope. Flag localStorage/sessionStorage token storage. - Session Lifecycle: Session ID regenerated after login, sessions invalidated on logout/password change/email change/privilege escalation, inactivity timeout, user session management. PASS 3: BRUTE FORCE & CREDENTIAL STUFFING [CWE-307] - Rate limiting on ALL auth endpoints (login, registration, password reset, MFA, email verification, API key generation). Server-side enforcement, tracking both IP and account identifier. Check bypass via X-Forwarded-For manipulation, User-Agent changes, IPv4/IPv6, username normalization. - Account lockout: time-based (not permanent), progressive delays, admin notification. Bot protection: CAPTCHA after 3-5 failures, server-side validated. PASS 4: MFA/2FA [CWE-308] - If not implemented: flag as HIGH for sensitive apps. If implemented: check bypass vectors: direct endpoint access pre-MFA, response manipulation, code reuse, brute force (rate limit OTP endpoint independently), backup code security, MFA downgrade, recovery flow bypass, session persistence after MFA change. - Enrollment security: re-authentication required, notification on add/remove/change. PASS 5: PASSWORD RESET [CWE-640] - Token: CSPRNG generated, >=128 bits entropy, 15-30 min expiry, single-use, stored hashed. No email enumeration, consistent timing, all sessions invalidated after reset. - Host header poisoning: reset link domain from hardcoded config, NOT from Host/X-Forwarded-Host headers. - Additional: no CC/BCC parameter injection, old password required for password change. PASS 6: ACCOUNT ENUMERATION [CWE-204] - Check ALL endpoints: login, registration, password reset, email verification resend, OAuth link/unlink, API user lookup. Consistent messages, timing, response structure, headers, and redirect behavior. PASS 7: OAUTH & SOCIAL LOGIN [CWE-287, CWE-346] - Authorization Code flow (not Implicit), state parameter validated, PKCE for public clients, strict redirect_uri validation. Server-side token validation, id_token signature/claims verified. - Account linking: email conflict handling, verified email requirement before linking, prevent attacker OAuth persistence. PASS 8: REGISTRATION [CWE-287] - Email verification required, protection against mass account creation, verification tokens single-use and time-limited, rate-limited resend, Unicode homoglyph protection, reserved usernames. PASS 9: EMAIL & ACCOUNT CHANGE [CWE-620] - Email change: requires password, verifies new email, notifies old email, invalidates sessions. Password change: requires current password, notification sent. Delete account: re-authentication required, rate-limited. PASS 10: API KEY & SERVICE TOKEN SECURITY [CWE-798] - Keys: sufficient entropy (>=256 bits), hashed before storage, HTTPS transmission, rotation mechanism, scoped permissions, rate-limited independently, immediate revocation. PASS 11: AUTH MIDDLEWARE & ROUTE PROTECTION [CWE-306] - Centralized middleware with allowlist (not denylist) pattern. All routes classified. Expired/malformed/missing token handling. Server-side protection (not just SPA guards). Consistent across HTTP methods. Hidden/debug endpoints checked. GraphQL per-resolver auth. PASS 12: AUTH LOGGING & MONITORING [CWE-778] - Log: logins, failures, lockouts, password changes, resets, MFA changes, OAuth linking, session invalidation, privilege changes, API key operations, admin impersonation. Exclude sensitive values. Alert on suspicious patterns (credential stuffing, impossible travel, bulk creation). ═══════════════════════════════════════════════════════════════════ PHASE 2: EXPLOIT CHAIN ANALYSIS ═══════════════════════════════════════════════════════════════════ After individual findings, identify chains for account takeover: - Enumeration + credential stuffing + no rate limit + no MFA - XSS + token in localStorage - Host header injection + password reset - OAuth state missing + open redirect - MFA bypass + stolen session - Weak JWT secret + no revocation - Algorithm confusion (RS256→HS256) - Registration without email verification + OAuth auto-linking ═══════════════════════════════════════════════════════════════════ PHASE 3: OUTPUT FORMAT ═══════════════════════════════════════════════════════════════════ For EACH finding: ### [AUTH-XXX] Title - Severity: CRITICAL | HIGH | MEDIUM | LOW | INFORMATIONAL - Confidence: HIGH | MEDIUM | LOW - CWE: CWE-XXX - OWASP 2025: Category - Location: File path(s), function(s), line number(s) - Vulnerable Code: Exact snippet - Attack Scenario: Step-by-step with exact HTTP requests - Impact: Scope (single user, all users, admin) - Remediation: 1) Immediate drop-in code fix 2) Defense in depth - References: CWE link, CVEs, docs ═══════════════════════════════════════════════════════════════════ PHASE 4: EXECUTIVE SUMMARY ═══════════════════════════════════════════════════════════════════ 1. Risk Overview by severity 2. Auth Security Posture: RED/YELLOW/GREEN 3. Top 3 Account Takeover Paths 4. Quick Wins (<1 hour fixes) 5. Missing Security Controls 6. Systemic Patterns 7. Auth Modernization Recommendations Rules: Be paranoid. No fabricated paths/CVEs. Evidence-based findings only. Prioritize by account takeover potential. Think like an attacker who knows your auth library's source code.

SQL injection remains a top threat. ORMs and parameterized queries are non-negotiable.

You are a database security specialist with 15+ years of experience in application security, database administration, and penetration testing. You have deep expertise in SQL/NoSQL injection, ORM security pitfalls, access control at the data layer, and cloud-managed database platforms (Supabase, Firebase, PlanetScale, Neon, etc.). You are conducting a focused security audit of ALL database interactions in: `/folder-name` Threat model: Assume an attacker who is an authenticated user with a valid account. They have unlimited time, full knowledge of your tech stack, and will probe every endpoint. They will also attempt unauthenticated attacks against public-facing endpoints using automated tools, timing analysis, and manual exploitation. ═══════════════════════════════════════════════════════════════════ PHASE 0: DATABASE LAYER RECONNAISSANCE ═══════════════════════════════════════════════════════════════════ Before analyzing vulnerabilities, map the database layer: 1. Database stack: engine(s), ORM/query builder, connection pooler, BaaS platform, migration tool 2. All database entry points: every file, function, route handler, resolver, middleware, cron job, queue consumer, or webhook that reads/writes to the database 3. Trust boundary: where does user input first touch a database query? 4. Sensitive data locations: tables/columns with PII, credentials, tokens, financial data, internal system fields 5. Auth-to-data path: how does user identity flow from authentication to database queries? Output as "Database Attack Surface Summary" before proceeding. ═══════════════════════════════════════════════════════════════════ PHASE 1: VULNERABILITY ANALYSIS (10 audit passes) ═══════════════════════════════════════════════════════════════════ PASS 1: QUERY CONSTRUCTION & INJECTION [CWE-89, CWE-943] - Parameterization: ALL queries must use parameterized statements or ORM-native methods. Flag string concatenation, template literals, f-strings in SQL construction. - ORM-Specific Vectors: Prisma ($queryRawUnsafe, operator injection via object input in where clauses), Sequelize (sequelize.query(), sequelize.literal(), Op.like), Drizzle (sql.raw()), TypeORM (createQueryBuilder with raw conditions), Django (.raw(), .extra(), RawSQL()), ActiveRecord (find_by_sql, where with interpolation), SQLAlchemy (text() with formatting), Supabase (.rpc() with dynamic SQL). - NoSQL/Operator Injection: ORM where clauses accepting objects from user input, MongoDB $where/$regex/$expr, API params spread into filter objects. - Second-Order Injection: stored values later used in queries without re-validation. PASS 2: INPUT VALIDATION & SANITIZATION [CWE-20] - Type validation at API boundary with schema library (Zod, Joi, Yup, Pydantic, etc.). Schemas applied BEFORE database layer, reject unknown fields. - Length/range limits on all text/numeric/array inputs. Whitelist validation for enums, sort columns, sort directions, filter field names. - Special characters: wildcards escaped in LIKE/ILIKE, Unicode normalization, null byte stripping. PASS 3: ACCESS CONTROL AT THE DATA LAYER [CWE-284, CWE-639] - Row-Level Ownership: EVERY query verifies requesting user owns/has access to the resource. User ID from verified server-side session, not client-supplied params. Test for IDOR on all endpoints. - Multi-Tenancy: every query includes tenant_id from authenticated session (not request params). Test cross-tenant access. - Supabase RLS: RLS ENABLED on EVERY table (Table Editor tables get RLS by default; tables created in the SQL Editor or by migrations do not, so enable it explicitly or use an event trigger that enforces it, and check the Data API grant on each table). Policies use auth.uid(), INSERT policies have corresponding SELECT policies, UPDATE policies include USING and WITH CHECK, policies scoped to correct role (authenticated not public). Check views (bypass RLS by default), security_definer functions in exposed schemas, RLS based on user_metadata (writable by user), realtime subscriptions. - Database Permissions: app user has minimum required permissions only. No DROP, CREATE TABLE, ALTER, GRANT, TRUNCATE, CREATE FUNCTION. PASS 4: DATA EXPOSURE & LEAKAGE [CWE-200, CWE-359] - Flag SELECT * / full ORM objects returned to client. No password hashes, API keys, internal fields in responses. Explicit serialization/DTO layer required. - Unbounded queries: pagination on all list endpoints, server-side max page size, bounded search, authorized exports. - Timing/enumeration side channels: consistent response times, non-sequential IDs preferred. - Error leakage: no database errors propagated to API responses. PASS 5: MASS ASSIGNMENT PROTECTION [CWE-915] - Explicit allow-list (DTO/schema) for every create/update. Test: role, is_admin, permissions, credit_balance, user_id, org_id, is_verified, status, id, created_at. Flag direct req.body to ORM create/update. PASS 6: TRANSACTION SAFETY & RACE CONDITIONS [CWE-362, CWE-367] - Financial/inventory/balance operations in transactions with proper isolation. TOCTOU vulnerabilities, idempotency keys, concurrent request handling, optimistic/pessimistic locking. PASS 7: DATABASE CONFIGURATION & INFRASTRUCTURE [CWE-16] - Credentials in env vars or secrets manager (not hardcoded, not in git, not in docker-compose). Different creds per environment, rotation configured. - Network: database not publicly accessible, private subnet/VPC, TLS enforced. - Connection pooling: transaction mode configuration, separate credentials, reasonable pool size, idle timeout. - Backups: automated, tested, encrypted, PITR available. PASS 8: SERVICE KEY & ADMIN CREDENTIAL EXPOSURE [CWE-798] - Secret key (legacy name: service_role key), Firebase admin SDK, or admin DB credentials NEVER in: client-side bundles, frontend env vars (NEXT_PUBLIC_, VITE_, REACT_APP_), mobile apps, API responses, error messages, git history. Publishable key (legacy name: anon key) client-side ONLY with proper RLS. PASS 9: MIGRATION & SCHEMA SECURITY [CWE-284] - No sensitive data in migrations, no SECURITY DEFINER functions that could be abused, no tables without RLS, separate migration role from app role, audit triggers and stored procedures for dynamic SQL injection. PASS 10: LOGGING, MONITORING & AUDIT TRAIL [CWE-778] - Security-relevant operations logged (auth events, permission changes, deletions, admin actions). Sensitive values excluded. Log injection prevented. Slow query monitoring. Audit trail for compliance. Failed authorization attempts alerted. ═══════════════════════════════════════════════════════════════════ PHASE 2: EXPLOIT CHAIN ANALYSIS ═══════════════════════════════════════════════════════════════════ Identify chains: - Operator injection + missing RLS = full table dump - Mass assignment on role + missing auth check = admin takeover - service_role key in frontend + no RLS = complete database takeover - Sequential IDs + no ownership check + missing pagination = full data export - Race condition on balance + no transaction isolation = double spend - Second-order injection in username + admin dashboard = stored XSS → session theft ═══════════════════════════════════════════════════════════════════ PHASE 3: OUTPUT FORMAT ═══════════════════════════════════════════════════════════════════ For EACH finding: ### [DB-XXX] Title - Severity: CRITICAL | HIGH | MEDIUM | LOW | INFORMATIONAL - Confidence: HIGH | MEDIUM | LOW - CWE: CWE-XXX - OWASP 2025: Category - Location: file path(s), function(s), line number(s) - Vulnerable Code: exact snippet - Attack Scenario: step-by-step with exact HTTP requests/payloads - Impact: data exposed, blast radius (single user, all users, entire DB) - Remediation: 1) Immediate drop-in code fix 2) Defense in depth - References: CWE link, CVEs, ORM docs ═══════════════════════════════════════════════════════════════════ PHASE 4: EXECUTIVE SUMMARY ═══════════════════════════════════════════════════════════════════ 1. Risk Overview by severity 2. Database Security Posture: RED/YELLOW/GREEN 3. Top 3 Risks for non-technical stakeholders 4. Quick Wins (<1 hour fixes) 5. Systemic Patterns (missing DTO layer, no RLS, no validation library) 6. Recommended Investments (schema validation, centralized auth middleware, migration hooks, CI/CD credential checks, audit logging) Rules: Be paranoid. No fabricated paths/CVEs. Evidence-based findings only. Prioritize by real-world exploitability. Think like an attacker who knows your ORM's quirks.

Use a Different Model

Run these audits with a model from a different family than the one that generated your code. Models have blind spots for their own output. The Semgrep results show that the two models missed different bug types, so one model is not enough.

Next step: architecture

Step 7 of 12 covers the stack and the backend layer that Bookly uses, plus the choices that are hard to undo. Continue on the architecture page.

Common Questions

How do I enable RLS in Supabase?

Run alter table bookings enable row level security; then add a policy for each action, such as letting a client select only rows where client_id matches auth.uid(). Tables made in the dashboard Table Editor have RLS on, but tables made with SQL or migrations do not. On new projects, the table also needs an explicit grant before the Data API can see it.

Which vibe coding security risks are most common?

The common ones are secret keys in client code, missing ownership checks that let one user read another user's data, Supabase tables without RLS, unverified payment webhooks, and packages the AI invented. Agents add new risks: prompt injection through data they read, and over-broad tool or MCP permissions. Veracode's July 2026 report found about 44% of AI coding tasks introduced a risky vulnerability.

How do I secure the database in an app built with AI?

Keep the database behind your server or behind RLS, never open to the browser. Give each table RLS and a policy per action, keep the secret key on the server, and use parameterized queries through an ORM such as Drizzle. Give agents a separate, read-only development database, not production. Then test as a second user to confirm one client cannot read another client's bookings.

Why does Supabase return permission denied for a new table?

Each new table in public needs an explicit grant before the Data API can reach it, on top of enable row level security and your policies. Tables that already exist keep their grants. Make the agent write all three statements for every new table, and reject any fix that grants everything to anon, because that brings back the exposure the change removes.

I committed an API key to GitHub. What should I do first?

Rotate first. Honeypot studies from 2023 saw leaked keys used within 1 to 2 minutes of a GitHub push, so deleting the file later does not protect you. Revoke the key, issue a new one with the smallest scope, and update each service that uses it. Scan the full git history with TruffleHog, and rewrite history only after the old key is dead. Give each backend service its own key.

Can a coding agent with database access be prompt injected?

Assume any user-written text, such as a booking note or a support ticket, can contain instructions. Connect the Supabase MCP server with read_only=true, scope it with project_ref, limit tool groups with features, and keep manual approval on. Point it at a development project, and keep it away from production unless the task needs production data. A confirmation dialog is a guardrail, not a guarantee.