In short
- Cursor's own terms for hosted apps say it is not responsible for your apps, your prompts or the outputs. Its reviews and checks reduce mistakes; what your live app lets a stranger do is on you.
- Bugbot and Security Review read code changes. They cannot see a Supabase table created in the dashboard, Firebase rules deployed from the console or environment variables set on your host.
- A rule in
.cursor/rulesloads in every chat only if it is an.mdcfile withalwaysApply: true. A plain.mdfile there is ignored, Bugbot does not read these rules at all, and rules steer the agent without enforcing anything. - Generated code fails security tests often: Veracode found OWASP Top 10 flaws in 45% of its AI coding test cases, and code models regularly suggest npm and PyPI packages that do not exist.
- The leaks that matter show up on the deployed app: test it signed out and with two accounts, then again after every deploy.
On this page
- Two questions behind "is Cursor safe"
- The stack Cursor writes, and where it leaks
- What AI-generated code gets wrong
- What Cursor's own checks catch
- How to check an app built with Cursor
- Fixes, with prompts to give Cursor's agent
- Make the rules stick: rules, hooks and ignore files
- Test the live app, and again after every deploy
- Cursor app security checklist
- Questions
- Sources
Two questions behind "is Cursor safe"
People who search for Cursor security usually mean one of two things. The first is the editor itself: what its agent may run on your machine. By default the agent asks before it runs a terminal command, but Workspace Trust is off, and Cursor's own security page suggests opening repositories you do not trust in a plain text editor. The second is the app you shipped with it: can a stranger read your users' data, use your API keys or skip your paywall. This page is about the second question, because that is where the damage lands.
Cursor is an AI code editor with an agent that writes and edits code and runs commands, on your machine or on Cursor's cloud agents. Those cloud agents can also host the apps they build. Its documentation for that hosting is explicit: Cursor provides tools, "and are not responsible for your apps, including your prompts and any outputs." That is a fair line to draw, and it tells you where your part starts.
| Layer | What Cursor does | What stays with you |
|---|---|---|
| Writing code | The agent writes what you ask, steered by your rules and the files it reads | Reading the diff and deciding what ships |
| Code review | Bugbot and Security Review comment on pull requests | Reading the findings, and making the check block a merge |
| Secrets on your machine | Files in .gitignore and .env* files are ignored by default | Keeping real keys off the machine, since the agent's terminal and MCP tools can still read ignored files |
| Hosting with Cursor's Apps | Isolated hosting, a Postgres database, Cursor sign-in for private apps, publish checks | Auth and per-user access in public apps, and what the app returns |
| Hosting elsewhere (Vercel, Netlify, a VPS) | Nothing: Cursor never sees the live app | Environment variables, headers, database rules, every deploy |
| Database rules (Supabase, Firebase) | Writes migrations and rules when you ask | Row level security on every table, rules deployed, buckets private |
The stack Cursor writes, and where it leaks
Cursor has no default stack. The agent writes whatever your repository already uses, or whatever your prompt names. The one exception is its own app hosting, called Apps, on paid plans with cloud agents: Cursor provisions a Postgres database if the app needs one, hosts it in a dedicated account isolated from other customers, keeps secrets you enter out of the agent's sight, and puts private and team apps behind Cursor sign-in. On individual plans you can share an app publicly, and then Cursor sign-in no longer applies.
Whatever the stack, the same layers leak, and each one has a way to fail that a stranger can find from the browser:
| Layer | Common choice | How it leaks | What Keybrum tries |
|---|---|---|---|
| Frontend bundle | Next.js, Vite with React | A secret key in a NEXT_PUBLIC_ or VITE_ variable, or source maps that publish your code | Finds keys in the JavaScript and checks whether they work |
| Database | Supabase, Firebase, Postgres | A table without row level security (RLS), or rules open to any signed-in user | Reads and writes tables as anon and as a fresh account |
| API routes | Route handlers, server actions, Express | The route checks that you are signed in, never that the record is yours | Account B requests account A's object |
| AI features | A route that calls OpenAI or Anthropic | The route answers without a session, so anyone spends your credits | Sends a short prompt with no session |
| Payments | Stripe | The webhook trusts events it never verified | Sends an unsigned event to your own webhook |
| Hosting | Vercel, Netlify, a VPS | A .env file served as a page, missing security headers | Requests the file and reads the headers |
The database row is not hypothetical. CVE-2025-48757 was assigned after a researcher found 170 of 1,645 Lovable apps, about one in ten, with missing or weak RLS. Nothing about that bug is specific to Lovable: a Supabase table created by a Cursor migration without enable row level security can be open in the same way. The Supabase RLS guide covers the policies.
What AI-generated code gets wrong
Three documented risks apply to any app written with Cursor's agent, whatever the model behind it.
Insecure patterns that still work
In July 2025, Veracode tested more than 100 language models on 80 coding tasks built around known weaknesses. In 45% of the test cases, the generated code introduced a vulnerability from the OWASP Top 10, and the models failed to defend against cross-site scripting in 86% of the relevant cases. Veracode also found that security results had not improved as newer models got better at writing code that compiles. The code runs, the screens look right, and the flaw sits in what the code does not check. The bug we see most in apps built with AI agents is exactly that: a route or a policy that checks the caller is signed in, and never checks that the row belongs to them. That is an IDOR vulnerability.
Packages that do not exist
A USENIX Security 2025 paper generated 576,000 code samples with 16 code models and found that at least 5.2% of the packages suggested by commercial models, and 21.7% for open-source models, did not exist: 205,474 distinct invented names. Anyone can publish a package under a name models tend to invent, with whatever code they like inside. When the agent adds a dependency, check in the diff that the package exists, that the name is the one you meant, and that someone maintains it.
Rules files you did not write
What Cursor's own checks catch
Cursor ships real security tooling, and it is worth turning on. Here is what each piece does, per Cursor's documentation.
Bugbot on pull requests
Bugbot reviews pull requests for bugs, security issues and code quality problems, and leaves comments with a suggested fix. It runs on every update of a pull request, or when someone comments cursor review or bugbot run. Its settings can live in .cursor/config/bugbot.yaml, which Bugbot reads from the branch the pull request merges into, so a pull request cannot change how it gets reviewed. Bugbot does not use your .cursor/rules files: put review rules, such as "flag any route that reads a record without checking its owner", in .cursor/BUGBOT.md.
One trap: when Bugbot finds issues, its GitHub check ends as neutral by default, not failure. Requiring the Cursor Bugbot check in branch protection makes sure it runs, but does not block a merge on findings. Turn on the fail-on-unresolved-issues setting if your organization has it.
Security Review and Vulnerability Remediation
Cursor launched Security Review in beta on Teams and Enterprise plans on 30 April 2026. A Security Reviewer checks every pull request for vulnerabilities, auth regressions, privacy and data-handling risks, agent tool auto-approvals and prompt injection, and comments on the exact line with a severity and a fix. Vulnerability Remediation scans the codebase on a schedule, and when you turn on its remediation settings, agents write tests to confirm each finding and open a draft pull request with the fix. You can plug your own SAST, dependency and secrets scanners in through MCP. Before you push, the /review-security command runs the same review on your branch from the agent, in Cursor 3.7 and later.
Publish checks on Cursor-hosted apps
Apps hosted by Cursor go through four checks on every publish, always on: the publish stops if a file contains an API key or access token, stops if it includes credential files such as private keys, leaves .env files out, and removes source maps. An AI review then reads the app's files and blocks serious issues, unless a team admin turned it off. Admins can also approve a publish the review blocked, except for malicious code, hardcoded secrets or exposed credentials. Public sharing is off by default for Teams and Enterprise. Apps hosted elsewhere have to catch these leaks themselves.
What none of them can see
All of these read your repository. A lot of what decides whether your app leaks lives somewhere else: RLS switched off in the Supabase dashboard, a Firebase rule deployed from the console, a storage bucket made public by hand, an environment variable on Vercel. A key that is not written in any file, but that a route returns to the browser at runtime, also passes a scan of the files. And a review reads one change at a time; it does not sign up twice and try to read the other account's invoices. That part needs a test of the running app.
How to check an app built with Cursor
Run these against your own app only, in this order.
- 1
Start with the outside view
Paste your app's address into the free check. In about ten seconds it shows the backend, any exposed keys and the tables named in your JavaScript, with no account and nothing sent to your backend.
- 2
Search your production build for secrets
Build the app and search the files that ship to the browser, with the command below. The API key leak checker does the same on a live address.
- 3
Check the database rules
On Supabase, run the queries from the RLS checker and open Security Advisor. On Firebase, paste your rules into the Firebase rules checker.
- 4
Try the two-account test
Create accounts A and B. As A, create a record and copy its ID from the browser's network tab. Sign in as B and request that ID, then request it signed out. B should get a 404, and the signed-out request a 401.
- 5
Call your AI routes without a session
In the network tab, copy the request your chat or generate feature sends (Copy as cURL), remove the
CookieandAuthorizationheaders, and run it. If a model answers, anyone can spend your credits. The unprotected AI endpoint guide shows the fix. - 6
Check files and headers
Request
/.envwith the command below, run the security headers checker, and if you use Next.js, check your version with the Next.js CVE checker.
npm run build
grep -rnoE "sk_live_[A-Za-z0-9]{10}|sk-proj-[A-Za-z0-9_-]{10}|sk-ant-[A-Za-z0-9_-]{10}|sb_secret_[A-Za-z0-9_-]{6}|BEGIN [A-Z ]*PRIVATE KEY" .next/static dist build 2>/dev/null
curl -s https://your-app.example/.env | head -n 5.next/static, Vite in dist. Any match is a key every visitor can read: rotate it, then move the call to the server. Legacy Supabase service role keys are JWTs, so paste those into the Supabase key checker. If the curl prints KEY=value lines, your .env file is public.Fixes, with prompts to give Cursor's agent
Cursor's agent can fix these once you name them precisely. Vague prompts like "make it secure" get vague results. These four prompts point it at one class of bug each and ask for a list before the change, so you can review it.
1. List every API route and server action in this repo. For each one, say how it gets the current user and whether it checks that the record it reads or changes belongs to that user. Fix the ones that do not, without changing what the owner sees.
2. Find every environment variable used in client code or prefixed NEXT_PUBLIC_ or VITE_. Flag any that holds a secret, move the call that needs it to a server route, and list the keys I must rotate.
3. List every table our migrations create. For each, confirm row level security is enabled and show its policies. Write one new migration that enables it where it is missing, with owner-only policies.
4. Find every route that calls OpenAI, Anthropic or another model. Make each one require a signed-in user and add a per-user daily limit.The first prompt is the one that matters most. Here is the change it should produce in a Next.js route, with the owner taken from the session instead of trusted from the URL:
// Before: any signed-in user reads any invoice by changing the id
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const invoice = await db.invoice.findUnique({ where: { id } });
return Response.json(invoice);
}
// After: the owner comes from the session, and the query checks it
export async function GET(req: Request, { params }: { params: Promise<{ id: string }> }) {
const session = await getSession();
if (!session) return new Response("Unauthorized", { status: 401 });
const { id } = await params;
const invoice = await db.invoice.findFirst({ where: { id, userId: session.user.id } });
if (!invoice) return new Response("Not found", { status: 404 });
return Response.json(invoice);
}getSession stands for your auth library's call. Return 404 rather than 403, so a stranger cannot tell which IDs exist.On Supabase, the third prompt should end in a migration like this one. The using clause compares the owner column to the caller's ID, which a policy that only says to authenticated never does. Wrapping auth.uid() in select lets Postgres evaluate it once per query instead of once per row.
alter table public.invoices enable row level security;
create policy "Owners read their invoices"
on public.invoices for select
to authenticated
using ((select auth.uid()) = user_id);with check, so a user cannot write rows owned by someone else.For keys already in the bundle, follow what to do when an API key leaks: rotate first, then fix the code, since the old build is cached in browsers and crawlers. For payments, the Stripe webhook guide shows the signature check. When Keybrum finds one of these, Cursor's agent reads the finding and the fix through Keybrum's MCP server, so it starts from the request that proved the leak instead of your description of it.
Make the rules stick: rules, hooks and ignore files
The agent can write the same bug again next week. Cursor gives you three places to set defaults.
A security rule that loads in every chat
---
description: Security rules for every change in this app
alwaysApply: true
---
- Never put a secret key in client code or in a variable prefixed NEXT_PUBLIC_ or VITE_. Secret keys are read on the server only.
- Every API route and server action takes the user from the session, never from the body or the URL, and checks that the record belongs to that user.
- Every new table enables row level security in the same migration, with policies that compare the owner column to auth.uid().
- Never accept role, plan, credits or admin flags from the client in create or update handlers.
- Routes that call an AI model require a signed-in user and a per-user limit.
- Stripe webhooks verify the signature on the raw body before doing anything.
- Ask before adding a dependency, and give the exact package name and why it is needed.
- Never render user input as HTML without sanitizing it..cursor/rules/security.mdc and commit it, so the rule is reviewed like code.Three details from Cursor's rules documentation trip people up. Project rules must use the .mdc extension: a plain .md file in .cursor/rules is ignored. Only alwaysApply: true puts the rule in every chat; otherwise the agent decides from the description whether to read it. And the current rules documentation covers .cursor/rules, Team Rules and AGENTS.md (the plain markdown alternative), but no longer the old single .cursorrules file, so move what it holds into one of those. On Team and Enterprise plans, Team Rules apply the same rule across every repository.
A rule is a prompt, not a lock. The model can still miss it on a long task, which is why the checks above still matter. Before you adopt a rules file someone else wrote, look for invisible characters:
LC_ALL=C.UTF-8 grep -rnP '[\x{200B}-\x{200F}\x{202A}-\x{202E}\x{2060}-\x{2064}\x{FEFF}\x{E0000}-\x{E007F}]' .cursor AGENTS.md .cursorrules 2>/dev/nullHooks that run on every edit
Cursor hooks run your scripts at fixed points of the agent loop and can observe, block or change what happens. An afterFileEdit hook runs after the agent edits a file and receives that file's path as JSON on standard input, which is the right moment for a secret scanner. It cannot undo the edit, so keep the scan in CI too. Project hooks in .cursor/hooks.json also run when Cursor's cloud agents work on the repository; hooks in your home folder do not.
{
"version": 1,
"hooks": {
"afterFileEdit": [{ "command": ".cursor/hooks/scan-secrets.sh" }]
}
}.cursor/hooks.json. Project hooks run from the repository root, so the path starts at .cursor/. The script can pass the file to the secret scanner you already use and log what it finds.Ignore files keep secrets out of context, mostly
Cursor ignores files listed in .gitignore and .env* files by default, and .cursorignore adds your own patterns. Its documentation is candid about the limit: the terminal and MCP tools the agent uses cannot be blocked from reading ignored files, and complete protection is not guaranteed. Keep production keys out of your local .env where you can, and give the agent test keys.
Test the live app, and again after every deploy
Code review happens before a merge. Your live app keeps changing after it: a new migration, a setting flipped in a dashboard, an environment variable added for a quick test. Can a signed-out visitor read a table? Can account B change account A's profile? Does the AI route answer without a session? Those have a yes or no answer, and the only way to get it is to send the request.
Keybrum sends those requests, on apps whose owner proved ownership. It runs more than 100 attacks across the layers in the table above, proves each finding with the request that worked, and attacks again after your fix. On a plan, it does that on every deploy.
Cursor app security checklist
.cursor/rules/security.mdcexists, hasalwaysApply: true, and is committed.- Every rules file you did not write was read and scanned for hidden Unicode.
- Bugbot or Security Review runs on every pull request, and unresolved findings fail the check where your plan allows it.
- No secret key in the production bundle, and none in a
NEXT_PUBLIC_orVITE_variable. - Every Supabase table has RLS on with owner policies, and Security Advisor findings are fixed or explained.
- Firebase rules deny by default and are deployed from the repository.
- Every API route takes the user from the session: account B gets a 404 on account A's records, a signed-out request gets a 401.
- Create and update handlers ignore role, plan and credit fields sent by the client.
- AI routes need a session and have a per-user limit.
- The Stripe webhook verifies signatures.
/.env,/.gitand source maps are not served, and security headers are set.- Every new dependency is a real package with the name you meant.
- The live app is tested again after each deploy.
The longer version, layer by layer, is the vibe coding security checklist. For the bugs behind each item, read vibe coding security risks.
Questions
Is Cursor safe?
As an editor, Cursor asks before its agent runs a terminal command by default, but Workspace Trust is off by default, so open repositories you do not trust in a plain text editor, as Cursor's docs advise. For the app you build, Cursor's terms for hosted apps say it is not responsible for your apps, prompts or outputs. Use its reviews, then test the live app yourself.
Does Cursor scan my code for security vulnerabilities?
Yes, in several ways. Bugbot reviews pull requests for bugs and security issues, Security Review (launched in beta for Teams and Enterprise in April 2026) checks every pull request and scans the codebase on a schedule, and /review-security runs a review from the agent before you push. All of them read code, so they miss settings that live in your database dashboard or your host.
Are Cursor generated code vulnerabilities common?
Generated code from any model often works while missing a check. Veracode found OWASP Top 10 flaws in 45% of its AI coding test cases. The most common one we see is a route that checks the user is signed in but never that the record is theirs.
How do I get Cursor to write safer code?
Add a security rule in .cursor/rules as an .mdc file with alwaysApply: true, give the agent precise prompts for one class of bug at a time, and read every diff. A hook on afterFileEdit can run a secret scanner on each change. Rules guide the model but do not enforce anything, so keep testing the result.
Is an app hosted by Cursor safe to share publicly?
Cursor blocks hardcoded keys, credential files, .env files and source maps on every publish, and runs an AI review unless an admin turned it off. A public app does not sit behind Cursor sign-in, so your own login and per-user access checks are what protect its data. Run the two-account test before you share the link.
Can Cursor read my .env file?
Cursor ignores .env* files and anything in .gitignore by default, so they stay out of its context. Its documentation warns that the agent's terminal and MCP tools cannot be blocked from reading ignored files. Keep production keys out of your local environment where you can.
Sources
- 1.Apps (hosting, publish checks and terms), Cursor Docs
- 2.Security Agents, Cursor Docs
- 3.Cursor Security Review, Cursor Changelog
- 4.Bugbot, Cursor Docs
- 5.Rules, Cursor Docs
- 6.Hooks, Cursor Docs
- 7.Ignore files, Cursor Docs
- 8.Agent security, Cursor Docs
- 9.New Vulnerability in GitHub Copilot and Cursor: How Hackers Can Weaponize Code Agents, Pillar Security
- 10.We Have a Package for You! A Comprehensive Analysis of Package Hallucinations by Code Generating LLMs, USENIX Security 2025
- 11.AI-Generated Code Poses Major Security Risks in Nearly Half of All Development Tasks, Veracode