Abbi Labs

Guides

Cursor-built app security checklist (from a security engineer)

By Pritesh Ghodge, Senior Solutions Engineer (cybersecurity) · Last updated 8 November 2026

Scan your app free — check what Cursor shipped to production.

Abbi Labs looks at your live site the way a stranger would: secret keys in the JavaScript, Supabase tables readable with your public key, exposed .env and .git files, source maps, and security headers. No sign-up for the quick check.

No sign-up. Read-only public-resource and protocol metadata checks. No model prompts or tool execution. Scan only sites you own or are allowed to test.

Run on every deploy or use from Cursor / Claude Code via MCP →

Weekly AI-app security checklist

One short email a week: a practical check for apps built with Supabase, Next.js and AI tools (RLS, leaked keys, headers and more). Unsubscribe anytime.

Cursor Agent can take you from a prompt to a Next.js (or Vite) app on Vercel with Supabase in an afternoon. What it can't know is what your data is supposed to be: which tables are public, which belong to one user, which keys can spend your money. Agent edits that "fix" an RLS error or move a key into NEXT_PUBLIC_ / VITE_ are a common way those mistakes land in production. Here is the checklist I'd run on a Cursor-built app before sharing it with real users.

1. Treat the published URL as the source of truth

Cursor works on your local project and git. Security for a stranger is whatever the deployed host serves. After every Agent change that touches env vars, auth, policies or API routes, open the published URL in a private window and re-check. The rest of this list is that outside view.

2. No secret keys in NEXT_PUBLIC_, VITE_ or client bundles

Anything with a NEXT_PUBLIC_ or VITE_ prefix is inlined into the JavaScript every visitor downloads. Fine for your site URL, analytics IDs and a Supabase publishable/anon key. Not fine for:

Those belong in host Environment Variables without the public prefix, read only from Server Components, Server Actions, Route Handlers or a backend. If a key was ever in the browser bundle, rotate it at the provider. Removing it from the code doesn't un-leak it.

Quick check on your published site: open DevTools → Sources (or search the JS files) for sk_live, sk-, sb_secret_ and service_role. More detail: NEXT_PUBLIC_ and VITE_ variables are shipped to every visitor. If the key was a service_role: what to do in the next 15 minutes.

3. Every Supabase table has RLS on, and policies check whose row it is

Many Cursor apps wire up Supabase. The publishable key in the browser is fine; Row Level Security is what stops that key reading everything. Two traps:

The 60-second test (use your project URL and the publishable key from your app):

curl -s "https://YOUR-PROJECT.supabase.co/rest/v1/orders?select=*&limit=1" \
  -H "apikey: YOUR_PUBLIC_KEY" \
  -H "Authorization: Bearer YOUR_PUBLIC_KEY"

[] or a permission error is what you want for private tables. A row of real data means anyone can read that table. Full walkthrough: how to check if your Supabase tables are readable by anyone.

For write policies an outside scan can't test (open INSERT/UPDATE, with check (true), grants), use the free Supabase RLS policy checker: one read-only SQL query, paste the result, analysed in your browser.

A prompt you can paste into Cursor Agent:

List every RLS policy in my database as a table: table, command
(select/insert/update/delete), role, and the exact USING and WITH CHECK
conditions. Flag RLS off, using (true), with check (true), and any
user-owned table whose policies never mention auth.uid(). Propose
owner-only policies. Show me the SQL before applying it.

4. Storage buckets aren't accidentally public

Public buckets (or storage.objects policies that let anon list/upload) expose uploads the same way open tables expose rows. List buckets and policies in the Supabase dashboard or SQL, and try listing with the public key. Private buckets plus per-user folder policies and signed URLs are the usual fix. Guide: Is your Supabase storage bucket public?

5. Server Actions and Route Handlers are still public endpoints

Moving an OpenAI or Stripe call into a Server Action or Route Handler hides the key. It does not hide the endpoint. If it doesn't check who is calling, anyone can use it to spend your credits or do whatever the function does. For each one, ask:

More detail in AI API key exposed in your frontend.

6. Nothing extra is published with your site

Cursor Agent sometimes creates or edits .env, commits secrets, or leaves source maps on. From a browser, try /.env, /.git/HEAD and a .map next to one of your JS files on your published URL. You want a 404 or your app's normal page, not a file. Next.js doesn't emit production source maps unless you turn them on; check productionBrowserSourceMaps (and any Vite/webpack map settings) if you or the Agent changed them. See exposed .env, .git and source maps.

7. Security headers on your Vercel (or other) host

A Content-Security-Policy, HSTS and clickjacking protection (X-Frame-Options or CSP frame-ancestors) are set by your host config, not by Cursor. Check what your published site sends with curl -sI https://your-app.vercel.app (and again on any custom domain) and add the missing ones in vercel.json or next.config headers. Examples: security headers for vibe-coded apps.

8. The two-account ownership test

No checklist beats this. Sign up as user A and create some data. Sign up as user B in a private window. As B, try to open A's pages by changing IDs in the URL, and watch the network tab for requests that return A's rows. Then sign out and try again as a visitor with the public key (the curl above). Only test projects you own.

9. Re-scan after every deploy

Every Agent prompt can change a policy or add a public env var, including an AI "fix" for an error. After you ship, run the outside check again (or let Monitor re-scan on deploy). A green local build does not mean the live bundle and policies are still safe.

What an outside scan adds, and what it can't do

Cursor edits your project. An outside scan checks what the published site actually serves to a stranger: the built JavaScript, the files on the host, the headers, and what your public key can read. It can't see your business rules or test as a signed-in user, so it doesn't replace the two-account test or reading your policies. Using both catches different mistakes.

Abbi Labs' free quick check covers leaked keys in JS, Supabase tables anyone can read with the public key (limit=1), exposed .env/.git, and security headers. Full scans on a verified domain also cover public storage buckets and source maps. For write-side RLS holes, pair it with the free RLS policy checker.

Keep it that way

Abbi Labs scans your live app for leaked keys, Supabase tables readable with your public key, exposed .env/.git files and security headers. Monitor re-scans weekly and after deploys, and emails you only when something new appears.

Scan your app free

FAQ

Does Cursor check my app's security?

Cursor (and its Agent/Composer) helps you write and edit code fast. It does not replace checking what your published URL actually serves to a stranger: the built JavaScript for secret keys, Supabase policies, exposed .env/.git/source maps, and security headers. Treat every Agent change that touches env vars, auth or database policies as something to re-verify on the live site.

Is it safe that my Supabase key is visible in my Cursor app?

The publishable (anon) key is designed to be public, as long as Row Level Security is on for every table and each policy only allows what you intend. Secret keys (service_role or sb_secret_, Stripe secret keys, OpenAI and other API keys) must never use a NEXT_PUBLIC_ or VITE_ prefix or appear in client bundles.

What does "cursor vercel supabase security" usually miss?

The usual misses are the same ones Abbi Labs scans for from the outside: a secret key inlined into the browser bundle via NEXT_PUBLIC_ or VITE_, Supabase tables readable with the public key because RLS is off or using (true), a production source map or .env/.git left reachable, missing security headers, and Server Actions or Route Handlers that anyone can call.

My Cursor Agent leaked an API key into the frontend. What now?

Rotate the key at the provider first if it was ever deployed. Move the call to a Server Action or Route Handler that checks the session, authorises the row, validates input and rate-limits anything that costs money. Remove the NEXT_PUBLIC_/VITE_ prefix, redeploy, and search the live JS for the old key. More detail: the AI API key and NEXT_PUBLIC_/VITE_ guides linked below.

Does Abbi Labs work with Cursor apps?

Yes. Paste your published Vercel or custom-domain URL. The free quick check needs no sign-up and looks at your home page headers, its JavaScript for secret keys, /.env and /.git, and whether Supabase tables your code queries (plus common names) return rows with your public key. Full scans on a domain you've verified you own add storage buckets and source maps. For write-side RLS holes, use the free in-browser policy checker.

Related guides

Weekly AI-app security checklist

One short email a week: a practical check for apps built with Supabase, Next.js and AI tools (RLS, leaked keys, headers and more). Unsubscribe anytime.