Security12 min read

How to Secure Cursor-Generated Code Before Launch: The Complete Security Checklist

Cursor-generated code ships with auth gaps, hardcoded secrets, and IDOR bugs. This security checklist audits every layer before your app reaches real users.

Knowing how to secure Cursor-generated code is the question most teams skip until they are already in front of a customer or responding to a security questionnaire. Cursor produces working code fast—faster than any developer can write equivalent functionality by hand—but the same patterns that make its output fast to generate make it predictable to exploit: authorization logic that authenticates without verifying ownership, SQL queries assembled by string concatenation when an ORM wasn't in context, and environment variables written directly into source files because the model followed the fastest path to a working prototype. The code compiles. The test passes. The vulnerability ships with it.

Cursor's security story is different from Lovable, Bolt, or Replit in one important way: Cursor is an IDE, not a deployment platform. You control the hosting, the environment, and the deployment pipeline. That shifts more responsibility to you, not less. Cursor doesn't default to a public source repository or inject secrets into a shared project link. But Agent Mode can execute shell commands on your machine without explicit review, MCP server integrations can access your local filesystem, and every file you haven't explicitly excluded via .cursorignore is fair game as model context—which means hardcoded credentials in a .env file can be read, echoed, or included in generated output without any warning.

This guide covers the security gaps that appear most consistently in Cursor-built applications: authorization logic that breaks under direct API calls, secrets that end up in source, and the gaps in what Cursor's SOC 2 certification actually protects. It applies the same review methodology Belsoft uses in security audits for AI-generated applications. For the full category overview, the companion post on vibe-coding security risks for enterprise teams covers how these patterns compare across tools.

Why Cursor-Generated Code Ships With Security Gaps

Cursor generates code by predicting the most likely continuation given the context in your project. That context is your existing code, open files, and the prompt you wrote. The model is not reasoning about your threat model. It is completing code patterns—and the most common patterns in its training data do not include complete authorization logic, comprehensive input validation, or security headers. Functional correctness and security correctness are different properties. A route that returns data when tested with your own account passes every functional test and fails every authorization test if it does not also enforce ownership.

  • →Authentication without authorization: Cursor generates routes that check whether the caller has a valid session token but frequently skip the second check—whether the caller owns the specific resource they are requesting. A route that validates the JWT and then returns the record by ID without filtering by user_id is broken in the most exploitable way. Any logged-in user can read any other user's data by substituting IDs.
  • →String-concatenated SQL queries: when Cursor cannot infer the ORM from context, it generates raw SQL by concatenating strings. String concatenation is the textbook SQL injection vector. The pattern is in its training data because it appears in documentation examples and Stack Overflow answers, where security is not the point. If you are not using an ORM with parameterized queries, every generated SQL statement needs a manual review.
  • →Hardcoded secrets and API keys: Cursor follows the fastest path to working code. When a service requires an API key and the key is not already referenced as an environment variable in the visible context, the model often writes the value inline. The credential ends up in source, which ends up in git, which ends up in your repository's history permanently unless you rewrite it—and rotation is still required regardless.
  • →Missing security headers: Cursor generates Next.js, Express, and similar applications without configuring Content-Security-Policy, X-Frame-Options, Referrer-Policy, or HSTS headers. The application works correctly without them. It is also trivially vulnerable to clickjacking, MIME-type sniffing, and a range of browser-level attacks that these headers prevent.
  • →Permissive CORS configuration: generated server code frequently uses CORS middleware with origin: '*' or includes the request origin unconditionally. This is the default that makes local development easy and production applications vulnerable to cross-origin data access.

Cursor Agent Mode: The Security Risks of Autonomous Code Execution

Agent Mode is the capability that makes Cursor qualitatively different from a code autocomplete tool. It takes a task description, plans a sequence of actions, and executes them autonomously—reading files, running shell commands, modifying source code, and installing dependencies without a checkpoint between each step. The output is genuinely impressive. The security implication is that the model is making execution decisions on your machine with limited checkpoints, and those decisions can be influenced by content the model reads during the task.

  • →Indirect prompt injection via project context: if your project includes a file with adversarial content—an imported npm package's README, a database record your code reads from a file, a malicious dependency's documentation—Agent Mode may incorporate instructions embedded in that content. The injection does not happen in your prompt. It happens in the context the agent assembles before acting. This is the standard attack surface for any AI agent that reads external content as part of its execution loop.
  • →Shell command execution without explicit review: Agent Mode runs terminal commands as part of its task execution. It can install packages, run migration scripts, modify configuration files, and execute arbitrary shell commands if the task requires it. Reviewing each command before execution is possible but easy to skip under deadline pressure, and the default behavior is to execute.
  • →MCP server filesystem access: Cursor's MCP server integration allows the agent to connect to local MCP servers that expose filesystem, database, and system operations as tools. An MCP server with broad filesystem permissions is a tool that the agent can use—or that a malicious prompt injection can leverage—to read files outside your project directory. Scope each MCP server's permissions to the minimum required for its task.
  • →Context window leakage: every file open in Cursor is potentially included in the context window sent to the model. If your .env file is open in an editor tab or not excluded via .cursorignore, its contents can appear in the prompt sent to the model API. Privacy Mode prevents prompt and code snippet logging on paid Business and Enterprise plans—and is not enabled by default on individual accounts.

What Cursor's SOC 2 Certification Actually Covers—and What It Does Not

Cursor holds a SOC 2 Type II certification, and this gets cited frequently when enterprise teams evaluate the tool for security-sensitive work. It is worth being precise about what that certification covers, because the scope is narrower than it sounds. SOC 2 Type II attests that Anysphere (Cursor's developer) has implemented and maintained controls over its own systems—the servers that process prompts, the infrastructure that stores account data, and the administrative controls over that infrastructure. The audit covers Cursor's security posture. It does not audit the security of the code Cursor generates, the MCP servers your team configures, the third-party VS Code extensions installed in the IDE, or the deployment infrastructure where your application runs.

For enterprise deployments, the Business and Enterprise plans add controls that matter in a security governance context: organization-wide Privacy Mode enforcement, SSO via SAML/OIDC, admin audit logs, and the ability to restrict which models developers can select. These are the controls your security team will ask about. They do not close the authorization, secrets, and injection gaps in generated code—they govern how Cursor is configured and how prompts are routed. The code review and CI security gate are still your responsibility.

Secrets and Credentials in Cursor-Generated Code

The most immediate and fixable security issue in Cursor-generated codebases is credential exposure. Cursor writes the fastest path to a working implementation, which often means writing API key values inline when they are not already defined as environment variables in the visible context. The credential ends up in the source file, the source file gets committed, and the git history preserves it permanently. Deleting the file does not remove the secret from history—git log -p shows every version of every committed file, and the credential is retrievable by anyone with read access to the repository now or in the future.

  • →Create a .cursorignore file at the project root: list every file that should never be read as model context. At minimum: .env, .env.local, .env.production, any file with 'secret' or 'credential' in the name, and any directory containing deployment keys. Without this file, any open editor tab is fair game as model context.
  • →Audit generated code for inline credentials before the first commit: search the entire diff for patterns like API key prefixes (sk-, pk-, AKIA, xoxb-, xapp-), connection strings containing passwords, and service_role keys. GitHub secret scanning catches many patterns automatically on push, but the credential is already in history before the alert fires. Run git diff --cached before every commit to review what is staged.
  • →Reference environment variables consistently as the pattern in your first prompt: when you establish process.env.OPENAI_API_KEY in your project's .cursor/rules file or initial prompt, Cursor is more likely to generate subsequent code that follows the same pattern. Always review generated credential handling—but providing the pattern reduces the frequency of inline values.
  • →Treat any secret that appeared in a committed file as compromised: rotation is required regardless of whether you believe anyone extracted it. The git history is durable and potentially accessible to anyone with read access to the repository. Rotate in the originating service, then clean the history with git filter-repo.
  • →Add a pre-commit hook or CI check for secret patterns: tools like git-secrets or gitleaks block commits that contain credential patterns before they reach the repository. This catches the model's tendency to hardcode values before they enter history.

Server-Side Authorization: The Critical Gap in Cursor-Generated APIs

Authorization is the most exploitable security gap in Cursor-generated code and the one that requires manual testing to catch. The model generates authentication logic—JWT verification, session checks—correctly in most cases. What it consistently misses is ownership verification: whether the authenticated user is allowed to access the specific record they are requesting. This is a two-step check that requires context the model does not have: the schema that defines which field connects users to records, and the business rule that says user A cannot read user B's data. The model generates the first check by pattern. The second requires your explicit instruction.

  • →Test authorization with two accounts before launch: create two test users and systematically attempt cross-user operations via direct HTTP requests, not via the UI. Try to fetch user A's resource as user B by substituting the resource ID in the URL. Try to update user A's profile as user B. Try to access admin routes as a standard user. If any of these succeed, the ownership filter is missing.
  • →Read user identity from the server-side session, never from the request body: every API route that accesses user data should extract the authenticated user's ID from the session token or verified JWT—not from req.body.userId or a query parameter. Cursor sometimes generates routes that accept userId from the client. Any logged-in user can substitute any user's ID in that payload.
  • →Add ownership filters to every database query by record ID: a route like GET /api/documents/:id should query WHERE id = $1 AND user_id = $2 with the session user's ID as the second parameter. Without the ownership filter, the route returns any record to any authenticated user. Review every Cursor-generated query that includes an ID parameter and confirm the ownership condition is present.
  • →Review middleware that reads but does not reject: Cursor sometimes generates auth middleware that reads the session token, attaches the user object to the request, and calls next()—even when the session is missing or invalid. Protected routes that depend on req.user being defined will throw a server error rather than correctly returning 401. Trace each middleware to confirm it returns early with an error response when auth fails.
  • →Never derive authorization from client-supplied role claims: admin routes that read role from the request body allow any authenticated user to add role: 'admin' to their payload and gain elevated access. Verify role from the server-side session or a database lookup on every privileged route.

Database Security in Cursor-Generated Applications

Cursor generates database integrations for whatever database your project uses. The security profile depends heavily on the database and the ORM in scope. PostgreSQL via Prisma or Drizzle is safer by default than raw pg queries; Supabase via the anon client is safer than Supabase via the service_role key. The consistent finding across Cursor-generated database code is that the service-level key that bypasses row-level security ends up in application code where the restricted anon key should be, and SQL built from string concatenation appears in routes that work but are injectable. For applications backed by Supabase specifically, the Supabase RLS security guide covers the database-layer authorization review in full detail.

  • →Review every SQL query for parameterization: search generated code for query patterns that concatenate strings (template literals inside SQL strings, + operators in query construction). Replace with parameterized queries or a type-safe ORM. Cursor-generated Prisma queries are parameterized by design—raw queries in executeRaw or queryRaw calls need individual review.
  • →Supabase service_role key must stay server-side only: the service_role key bypasses all Row Level Security policies. It should exist only in server-side environment variables, never in client-importable files or any utility that the frontend bundle can reach. Cursor sometimes generates Supabase client initializations that use service_role without distinguishing the server context from the client context.
  • →Verify RLS policies exist and are correct on every Supabase table: Cursor generates migration files that create tables but does not reliably add RLS policies. A table with RLS disabled returns all rows to any caller with the anon key. Review every generated migration and confirm RLS is enabled with explicit SELECT, INSERT, UPDATE, and DELETE policies.
  • →Use a database user with the minimum required permissions: the database user your application connects as at runtime should have SELECT, INSERT, UPDATE, DELETE on the specific tables it needs—not superuser permissions. Cursor generates connection configurations that often default to a privileged credential for development convenience.
  • →Run npm audit before every deployment: Cursor selects packages by familiarity, not by recency. Generated package.json files frequently reference versions carrying known CVEs. npm audit --audit-level=high before deployment catches the most critical findings before they reach production.

The Complete Cursor Security Checklist Before Going Live

Work through each item below before opening your Cursor-built application to real users. Run DeployReady (npx deployready) against your deployed URL first to get the automated baseline—security headers, OWASP patterns, exposed paths, and a 0–100 readiness score—then complete the manual authorization items that no scanner can test.

  • →.cursorignore created and committed: lists .env, .env.local, .env.production, and all credential files. No secrets file is readable as model context.
  • →Privacy Mode enabled at the organization level on Business or Enterprise plan: code and prompts are not used for model training.
  • →Inline credentials audit complete: searched all source files and git diff for API key patterns. No credential found outside environment variable references.
  • →Git history clean: any secret that appeared in a previous commit has been rotated in the originating service and removed from history via git filter-repo.
  • →Pre-commit secret scanning configured: git-secrets or gitleaks blocks credential patterns before they reach the remote repository.
  • →DeployReady run on deployed URL: security headers present, OWASP findings resolved, readiness score reviewed.
  • →Security headers configured in next.config.js or middleware: Content-Security-Policy, Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options, Referrer-Policy.
  • →CORS configuration explicitly allows only required origins: no origin: '*' in production API routes.
  • →Server routes read user identity from session token, not request body: no route accepts userId or role from req.body for authorization decisions.
  • →Every database query by record ID includes an ownership filter: both the record ID and the authenticated user's ID appear in every fetch, update, and delete query.
  • →Admin and privileged routes verify role from server-side session or database: no route reads role from the client request.
  • →Rate limiting on authentication endpoints: sign-in, sign-up, and password reset routes protected against brute force.
  • →All SQL queries use parameterized statements or a type-safe ORM: no string concatenation in database queries.
  • →Supabase RLS enabled on every table: explicit SELECT, INSERT, UPDATE, DELETE policies defined—no table relies on application-layer-only access control.
  • →Two-account authorization test passed: user B cannot read, modify, or delete user A's resources via direct API calls or URL manipulation.
  • →MCP server permissions reviewed and scoped: each configured MCP server has the minimum filesystem and system permissions required for its task.
  • →npm audit clean: no high or critical CVEs in production dependencies.

Frequently Asked Questions

Is Cursor-generated code secure for production use?

Cursor-generated code can be secure in production, but not by default. The model generates code that functions correctly and passes functional tests while containing authorization gaps, parameterization issues, and credential exposure that manual review catches. A systematic review against the checklist above, combined with automated scanning via DeployReady on the deployed URL and manual two-account authorization testing, is what closes the gap. The security work is not optional for any application that handles real user data.

What are the most common security vulnerabilities in Cursor-generated code?

The most consistent findings in Cursor-generated codebases are: missing ownership filters on database queries by ID (authentication without authorization, allowing any logged-in user to access any record by substituting IDs), string-concatenated SQL queries in routes where an ORM was not in context (SQL injection vectors), and hardcoded API keys or connection strings in source files when environment variables were not already established in the project context. Missing security headers and permissive CORS configuration appear in nearly every generated Next.js or Express application.

Does Cursor's SOC 2 Type II certification mean my app is secure?

No. Cursor's SOC 2 Type II certification covers Anysphere's own infrastructure—the systems that process your prompts and store your account data. It attests that Cursor's security controls have been audited and maintained. It does not audit the security of the code Cursor generates, the MCP servers your team configures, the VS Code extensions installed in the IDE, or the deployment infrastructure where your application runs. For enterprise teams, the SOC 2 cert is a prerequisite for vendor approval, not a substitute for auditing the code the tool produces.

How do I prevent Cursor from including my .env file in model context?

Create a .cursorignore file at the project root. Cursor respects it the same way Git respects .gitignore. Add .env, .env.local, .env.production, and any other file containing credentials or sensitive configuration. Without this file, any file open in an editor tab or in the project directory can be included in the context window sent to the model API. For teams using Agent Mode, also review which MCP servers are configured and what filesystem paths each one has access to—MCP server permissions are a separate, broader context channel that .cursorignore does not control.

What is indirect prompt injection in Cursor Agent Mode?

Indirect prompt injection occurs when malicious instructions are embedded in content that the agent reads during task execution—not in your prompt, but in a file, dependency, or external resource the agent includes in its context. An npm package README containing instructions formatted as agent directives, or a database record with embedded instructions, could influence Agent Mode's behavior without you prompting for it. The defense is restricting Agent Mode to trusted context sources, reviewing which files it reads as part of task execution, and keeping MCP server filesystem access tightly scoped to the directories the task actually needs.

How Belsoft Helps Secure Cursor-Built Applications

Belsoft runs structured security audits for teams that built with Cursor—or any AI coding tool—and need to confirm what is actually exposed before onboarding real users, responding to an enterprise security questionnaire, or making a customer-facing security commitment. The audit starts with DeployReady on the deployed URL to establish the automated baseline—security headers, OWASP Top 10 patterns, exposed paths, and a 0–100 readiness score. That takes minutes. The manual review that follows is what catches what no scanner can: authorization logic tested with real user accounts against the running application, database query ownership filters verified across every resource type, credential exposure checked across source and git history, and Agent Mode context paths reviewed for injection surface. We also cover the Lovable app security checklist and the full vibe-coded app category if your team uses multiple AI tools.

The deliverable is a ranked findings report with specific code changes for each issue—ready to implement, not just described—followed by a retest to confirm fixes before you share results with customers or a vendor security review. If you are preparing for an enterprise deal, responding to a security questionnaire, or you shipped fast on Cursor and want to know what is actually exposed, the starting point is a conversation. Book a call to discuss your Cursor-built app.

“Cursor writes code that works. Your job is to make sure it only works for the right people.”

Written by

Marco Silva

Security Engineer, Belsoft Solutions

Ready to partner?

Let's talk about your company.

30 minutes. No pitch. We talk through how you run today and where AI and automation would help.

Book a free audit
logo

Your AI & automation transformation partner: we audit, build, and train your team, then stay embedded as you grow.

Proud member ofNVIDIA Inception Program

Copyright Ⓒ 2026 BelSoft. All Rights Reserved.

BELSOFT, LDA · NIPC 517893258 · Lisbon, Portugal