pwnmyvibecode_

Is your v0 app secure?

v0 is Vercel's app builder, and it generates Next.js apps that deploy on Vercel, which is a secure host. Your v0 app is secure when no secret sits in a NEXT_PUBLIC_ variable, every server action and route handler checks who is calling, and you add the security headers Next.js does not set by default.

Updated

Check your live site now

Free, no signup, read only. A grade and plain fixes in seconds.

What v0 and Vercel handle, and what they don't

v0 writes Next.js code (React, Tailwind, shadcn/ui components) and deploys it to Vercel, which takes care of HTTPS, certificates and running your server code. When you connect a database or other service, its keys end up as environment variables on the Vercel project.

The generated code is where the security decisions are. v0 decides which components run in the browser and which on the server, where each API call happens, and whether a server action checks the session. It does what the prompt asks, so a vague prompt can produce a working app with the wrong defaults.

Security mistakes v0 apps commonly make

  • A key renamed with NEXT_PUBLIC_ so a client component can read it. In a client component, a variable without that prefix is undefined, which pushes toward the wrong fix. The right one is moving the call to the server.
  • A server action that takes a record ID from the form and updates it without checking that the signed-in user owns that record. Server actions are public endpoints.
  • A route handler under app/api that returns data to anyone who calls it.
  • No Content-Security-Policy, frame protection or Referrer-Policy.
  • A Supabase integration with tables that have row level security off.

Where the fixes go in a v0 project

  • Secrets: Vercel project environment variables without NEXT_PUBLIC_, read only in server components, server actions and route handlers.
  • Access checks: at the top of every server action and route handler that reads or changes user data.
  • Headers: next.config.ts (shown below) or vercel.json.
next.config.ts
const nextConfig = {
  async headers() {
    return [
      {
        source: "/:path*",
        headers: [
          { key: "Strict-Transport-Security", value: "max-age=31536000; includeSubDomains" },
          { key: "Content-Security-Policy", value: "default-src 'self' https: data: blob: 'unsafe-inline' 'unsafe-eval'; object-src 'none'; base-uri 'self'; frame-ancestors 'self'; form-action 'self'; upgrade-insecure-requests" },
          { key: "X-Frame-Options", value: "SAMEORIGIN" },
          { key: "X-Content-Type-Options", value: "nosniff" },
          { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
          { key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()" },
        ],
      },
    ];
  },
};

export default nextConfig;
app/actions.ts
"use server";

export async function updateNote(id: string, text: string) {
  const user = await getCurrentUser();
  if (!user) throw new Error("Not signed in");
  const note = await db.note.findUnique({ where: { id } });
  if (note?.ownerId !== user.id) throw new Error("Not allowed");
  await db.note.update({ where: { id }, data: { text } });
}
prompt for your agent
Review this Next.js app for security. Find any NEXT_PUBLIC_ variable that holds a secret and move the code that uses it into a server action or route handler. Make every server action and route handler check the signed-in user and that they own the record before reading or changing it. Add security headers in next.config.ts. List each change.

v0 app security checklist

  1. List the environment variables on the Vercel project. None with NEXT_PUBLIC_ should be a secret.
  2. Rotate any secret that was deployed with the prefix.
  3. Open every file with "use server" and every route handler. Each one that touches user data needs a user and ownership check.
  4. If you use Supabase, turn on RLS for every table and read the policies.
  5. Add security headers and redeploy.
  6. Scan the production URL.

How to verify your deployed v0 app

In the browser, open DevTools, Sources, and search the files under _next/static for your key prefixes (sk_live_, sk-, service_role). Then check headers with curl -sI on your production URL.

An outside scan does both automatically: it reads the HTML and your own JavaScript bundles for secret keys, checks for public .env and .git files, grades each security header including how strict the CSP is, and checks the https redirect, cookie flags and CORS. It does not call your server actions or log in, so ownership checks need a code review. The checklist above covers where to look.

Questions

Is v0 safe to use?

Yes. It is a Vercel product and deploys to Vercel's infrastructure. The generated app still needs review for secrets, access checks and headers, as any app would.

Are server actions in my v0 app secure by default?

No more than any API endpoint. Anyone can call a server action directly, so each one has to check the signed-in user and what they are allowed to change.

Why is my API key undefined in a v0 component?

Client components only get variables prefixed NEXT_PUBLIC_. If the key is a secret, do not add the prefix. Move the call into a server action or route handler, where the unprefixed variable is available.