NEW: State of Vibe Coding Security 2026Read it →
67% of AI apps ship with critical vulnerabilities

Bolt.new Security Guide: 10 Critical Fixes Before Deploying

Bolt.new makes building fast. But fast doesn't mean safe. ShipSafe scanned 100 AI-generated repos and found 67% had critical vulnerabilities and 45% contained hardcoded secrets. This guide covers every issue we see in Bolt.new projects and how to fix each one.

Why Bolt.new Apps Need a Security Review

Bolt.new generates full-stack applications in minutes. The AI optimizes for "does it work?" not "is it safe?" That means your app runs, but it probably:

  • Exposes API keys in client-side JavaScript bundles
  • Skips server-side authentication on API routes
  • Trusts all user input without validation
  • Uses wildcard CORS allowing any origin
  • Ships without security headers
  • Pulls dependencies without version pins

The UK NCSC CEO warned at RSA Conference 2026 that vibe coding poses "intolerable risks." Two days later, the litellm supply chain attack proved why: 47,000 downloads of poisoned packages in 46 minutes.

1

Hardcoded API Keys and Secrets

CRITICAL - 45% of AI projects affected

Bolt.new frequently puts API keys directly in frontend code. Anyone who opens browser DevTools can see them. This includes Stripe keys, Supabase service keys, OpenAI keys, and database connection strings.

⚠ Vulnerable Pattern

// Client-side code - EXPOSED in browser
const OPENAI_KEY = "sk-proj-abc123..."
const STRIPE_KEY = "sk_live_..."
const DB_URL = "postgresql://user:pass@host/db"

✓ Fixed Pattern

// .env file (never commit this)
OPENAI_API_KEY=sk-proj-abc123...
STRIPE_SECRET_KEY=sk_live_...
DATABASE_URL=postgresql://user:pass@host/db

// Server-side API route only
const openai = new OpenAI({
  apiKey: process.env.OPENAI_API_KEY
})

Quick Check

# Search for exposed secrets in your project
grep -rn "sk-proj\|sk_live\|sk_test\|apiKey.*=.*['"]" src/ --include="*.ts" --include="*.tsx" --include="*.js"

# Check if .env is in .gitignore
grep ".env" .gitignore
2

Missing Server-Side Authentication

CRITICAL

Bolt.new often generates authentication that only runs in the browser. A user can bypass it entirely by calling your API endpoints directly with curl or Postman. If your API route doesn't verify the session server-side, it's open to anyone.

⚠ Vulnerable Pattern

// API route with NO auth check
export async function GET(request: Request) {
  const users = await db.query("SELECT * FROM users")
  return Response.json(users) // Anyone can access
}

✓ Fixed Pattern

// API route WITH server-side auth
export async function GET(request: Request) {
  const session = await getServerSession(authOptions)
  if (!session?.user) {
    return Response.json({ error: "Unauthorized" }, { status: 401 })
  }
  // Only return THIS user's data
  const users = await db.query(
    "SELECT * FROM users WHERE id = $1",
    [session.user.id]
  )
  return Response.json(users)
}
3

No Input Validation

CRITICAL

AI-generated code trusts user input. It rarely adds validation or sanitization. This opens the door to SQL injection, XSS (cross-site scripting), and command injection. Georgia Tech found 35 new CVEs in March 2026 alone from AI-generated code, many involving injection vulnerabilities.

⚠ Vulnerable Pattern

// Direct string interpolation = SQL injection
const result = await db.query(
  `SELECT * FROM users WHERE email = '${req.body.email}'`
)

// Rendering user input directly = XSS
<div dangerouslySetInnerHTML={{ __html: userComment }} />

✓ Fixed Pattern

// Parameterized queries prevent SQL injection
const result = await db.query(
  "SELECT * FROM users WHERE email = $1",
  [req.body.email]
)

// Validate with zod before processing
import { z } from "zod"
const schema = z.object({
  email: z.string().email().max(255),
  name: z.string().min(1).max(100).trim(),
})
const validated = schema.parse(req.body)
4

No Rate Limiting

HIGH

Bolt.new never adds rate limiting. Without it, attackers can brute-force login forms, spam your API (running up your cloud bills), or scrape all your data. If you're using OpenAI or Stripe, an unprotected endpoint means someone else runs up your bill.

✓ Add Rate Limiting

// Using upstash/ratelimit (works with serverless)
import { Ratelimit } from "@upstash/ratelimit"
import { Redis } from "@upstash/redis"

const ratelimit = new Ratelimit({
  redis: Redis.fromEnv(),
  limiter: Ratelimit.slidingWindow(10, "60 s"),
})

export async function POST(request: Request) {
  const ip = request.headers.get("x-forwarded-for") ?? "127.0.0.1"
  const { success } = await ratelimit.limit(ip)
  if (!success) {
    return Response.json({ error: "Too many requests" }, { status: 429 })
  }
  // ... handle request
}
5

Missing Security Headers

HIGH - 0% of tested apps pass

Tenzai tested 15 vibe-coded apps for security headers. Zero out of 15 had any security headers configured. No Content-Security-Policy, no X-Frame-Options, nothing. Security headers are your browser-level defense layer.

✓ Add to next.config.js or middleware

// next.config.js
const securityHeaders = [
  { key: "X-Content-Type-Options", value: "nosniff" },
  { key: "X-Frame-Options", value: "DENY" },
  { key: "X-XSS-Protection", value: "1; mode=block" },
  { key: "Referrer-Policy", value: "strict-origin-when-cross-origin" },
  { key: "Permissions-Policy", value: "camera=(), microphone=(), geolocation=()" },
  {
    key: "Content-Security-Policy",
    value: "default-src 'self'; script-src 'self' 'unsafe-inline'; style-src 'self' 'unsafe-inline'"
  },
  {
    key: "Strict-Transport-Security",
    value: "max-age=63072000; includeSubDomains; preload"
  },
]

module.exports = {
  async headers() {
    return [{ source: "/(.*)", headers: securityHeaders }]
  },
}
6

Wildcard CORS Configuration

HIGH

Bolt.new defaults to Access-Control-Allow-Origin: *. This means any website can make requests to your API. An attacker can build a page that calls your endpoints on behalf of logged-in users.

✓ Restrict CORS

// middleware.ts
const ALLOWED_ORIGINS = [
  "https://yourdomain.com",
  "https://app.yourdomain.com",
]

export function middleware(request: NextRequest) {
  const origin = request.headers.get("origin")
  if (origin && !ALLOWED_ORIGINS.includes(origin)) {
    return new Response("Forbidden", { status: 403 })
  }
  // Set specific CORS headers
  const response = NextResponse.next()
  if (origin && ALLOWED_ORIGINS.includes(origin)) {
    response.headers.set("Access-Control-Allow-Origin", origin)
    response.headers.set("Access-Control-Allow-Methods", "GET, POST")
    response.headers.set("Access-Control-Allow-Credentials", "true")
  }
  return response
}
7

Missing Object-Level Authorization

HIGH

Even with authentication, Bolt.new apps often let any logged-in user access any other user's data. If your API takes an ID parameter and returns data without checking ownership, it's an IDOR (Insecure Direct Object Reference) vulnerability.

⚠ Vulnerable

// Any user can access any order by changing the ID
GET /api/orders/123  // Returns order 123 regardless of who's asking

✓ Fixed

// Always filter by the authenticated user
const order = await db.query(
  "SELECT * FROM orders WHERE id = $1 AND user_id = $2",
  [orderId, session.user.id]
)
if (!order) return Response.json({ error: "Not found" }, { status: 404 })
8

Insecure File Uploads

MEDIUM

If your Bolt.new app accepts file uploads, the generated code probably doesn't validate file types, check sizes, or scan for malicious content. An attacker can upload a web shell disguised as an image and execute arbitrary code on your server.

✓ Secure Upload Handling

const ALLOWED_TYPES = ["image/jpeg", "image/png", "image/webp", "application/pdf"]
const MAX_SIZE = 5 * 1024 * 1024 // 5MB

export async function POST(request: Request) {
  const formData = await request.formData()
  const file = formData.get("file") as File

  // Validate type
  if (!ALLOWED_TYPES.includes(file.type)) {
    return Response.json({ error: "Invalid file type" }, { status: 400 })
  }

  // Validate size
  if (file.size > MAX_SIZE) {
    return Response.json({ error: "File too large" }, { status: 400 })
  }

  // Generate random filename (never use original)
  const ext = file.type.split("/")[1]
  const filename = `${crypto.randomUUID()}.${ext}`
  // Upload to cloud storage, not local filesystem
}
9

Unpinned Dependencies

MEDIUM - 88% of litellm dependents were unpinned

The litellm supply chain attack (March 2026) compromised 47,000 installs in 46 minutes. Of the 2,337 packages that depend on litellm, 88% had no version pin. The telnyx package was hit 3 days later by the same attacker. Using ^ or ~ in your package.json means you auto-install whatever the registry serves, including poisoned versions.

✓ Pin Everything

# Lock exact versions
npm config set save-exact true

# Review what you're pulling
npm audit

# Use lockfile integrity
# Commit package-lock.json
# Enable npm audit in CI/CD pipeline

# Check for known compromised packages
npx is-my-node-app-secure
10

Verbose Error Messages

MEDIUM

Bolt.new apps typically expose full stack traces, database connection strings, and internal paths in error responses. This tells attackers your tech stack, file structure, and database type. Free reconnaissance.

✓ Safe Error Handling

// Global error handler
export function middleware(request: NextRequest) {
  try {
    return NextResponse.next()
  } catch (error) {
    // Log full error server-side
    console.error("Request error:", error)

    // Return generic message to client
    return Response.json(
      { error: "Something went wrong" },
      { status: 500 }
    )
  }
}

// Never do this in production:
// return Response.json({ error: error.message, stack: error.stack })

Pre-Deploy Checklist

Run through this before every Bolt.new deployment:

What Does a Security Audit Cost?

DIY (This Guide)

Free

  • ✓ Manual code review
  • ✓ grep-based secret scanning
  • ✓ npm audit
  • ✗ No automated scanning
  • ✗ No expert analysis
  • ✗ Easy to miss things
RECOMMENDED

notelon.ai Audit

$99

  • ✓ 50+ automated security checks
  • ✓ AI-powered fix suggestions
  • ✓ Copy-paste remediation code
  • ✓ Dependency vulnerability scan
  • ✓ Report within 24 hours
  • ✓ Follow-up scan included
Get Your Audit

Enterprise Agency

$2,500+

  • ✓ Manual pentesting
  • ✓ Compliance reporting
  • ✓ Dedicated team
  • ✗ 2-4 week turnaround
  • ✗ Overkill for most projects
  • ✗ 25x more expensive

Frequently Asked Questions

Is Bolt.new safe for production apps?
Bolt.new generates functional code quickly, but 67% of AI-generated apps ship with critical vulnerabilities (ShipSafe 2026). The generated code often includes hardcoded secrets, missing authentication, and no input validation. It requires a security review before production deployment.
What are the most common Bolt.new security issues?
Hardcoded API keys in client-side code (45% of projects), missing server-side authentication, no input validation (leading to XSS and injection), wildcard CORS, missing security headers, and unpinned dependencies. All of these are fixable with the patterns in this guide.
How much does a Bolt.new security audit cost?
Enterprise audits run $2,500-$10,000+. notelon.ai offers automated security audits starting at $99 for Bolt.new projects, covering 50+ checks with AI-powered fix suggestions. A free scan is also available for basic detection.
Can Bolt.new apps be hacked?
Yes. Georgia Tech found 35 new CVEs in March 2026 from AI-generated code. Common attack vectors include exposed API keys, SQL injection, broken authentication, and supply chain attacks. The litellm attack proved these aren't theoretical risks.
Does Bolt.new have built-in security?
Bolt.new runs in a WebContainer sandbox during development, but this doesn't protect your deployed app. Once you deploy to Vercel, Netlify, or any host, your app runs without sandboxing. All security must be in your code.

Don't Deploy Until You've Checked

Start with a free scan. If anything flags, the $99 audit gives you copy-paste fixes for every issue. Cheaper than one hour of incident response.