AI-coded apps

    Is the code Bolt.new generates safe to ship to production?

    A solo developer staring at the deploy console of a Bolt.new project the moment before pushing to production, with the package-lock.json open in one tab and the Supabase Table Editor open in another, RLS toggle still off

    By the time a developer ships a working app from Bolt.new in an afternoon, the question shifts. The generator produced something that runs in a browser. The harder question is whether the same code, the same dependencies, and the same backend wiring are safe to put in front of real users with real data.

    Short answer

    Bolt.new generated code is production-runnable, not production-ready. The default output works, but the same patterns that make Bolt.new fast (one-shot scaffolding, full npm dependency pulls, direct API integrations) ship a recognisable set of holes: hardcoded keys in the client bundle, Supabase Row Level Security disabled, no input validation on serverless functions, and a dependency tree built from whatever the AI called for that day. Each of those is fixable. None are caught for you.

    What you should know

    • Bolt.new compiles a real codebase. The generator emits a working Vite or Next.js project with real npm dependencies, real client and server code, and real environment variable handling. The output behaves like any other JavaScript project at audit time.
    • The default integration patterns prefer speed over isolation. Bolt.new often calls third-party APIs (OpenAI, Stripe, Supabase) directly from the client, with the key handed in as a Vite environment variable. That key ends up in the published bundle.
    • Supabase Row Level Security is opt-in. The Supabase anon key is publicly readable by design; the protection layer is RLS policies on each table. Bolt.new rarely generates those policies.
    • The npm tree reflects what the AI thought it needed. A Bolt.new project commonly carries 200 to 600 transitive dependencies. Some are well known. Some were called for by name based on a model's recall and may be typosquats or recently registered look-alikes.
    • Source maps and exposed env strings end up in the deploy. Vite ships source maps by default and inlines any import.meta.env.VITE_* variable into the bundle. Anything prefixed VITE_ is public.

    What does Bolt.new actually generate, and why does it matter for security?

    Bolt.new is an AI scaffolding tool that produces a working web application from a prompt. The output is a real npm project, typically Vite plus React, with a package.json, a lockfile, and direct integrations to Supabase or other backends-as-a-service. From a security stance, that means the same audit surface as any other modern frontend: a client bundle, a set of public environment variables, a backend configured by the developer, and a long dependency tree.

    The relevant primary documentation is the npm registry's audit guide, which is explicit about scope: npm audit reports known vulnerabilities from the advisory database. It does not flag malicious packages that have not yet been catalogued. A Bolt.new project that passes npm audit cleanly can still contain a freshly published typosquat. That distinction matters because AI scaffolding tools have a documented tendency to call packages by name based on a model's training-time recall, sometimes with hallucinated or stale names that attackers register proactively.

    Where do most Bolt.new production failures happen?

    In practice, the same five surfaces account for most of the production issues developers report after shipping a Bolt.new app.

    The first is keys in the client bundle. Anything prefixed VITE_ in the source ends up in the published JavaScript. Stripe secret keys, OpenAI keys, and Supabase service-role keys placed in .env with the wrong prefix become public. The fix is to put paid-API keys behind a serverless function and only expose anon-level keys to the client.

    The second is Supabase Row Level Security. With RLS disabled, the anon key allows any visitor to read or modify any row. The Supabase Row Level Security documentation is direct on the point: RLS is opt-in per table, and a project with public tables and no policies has no access control at the database layer. Bolt.new does not write those policies for you.

    The third is missing input validation. AI-generated serverless functions tend to trust the body they receive and pass values directly to downstream services. That includes paid APIs (OpenAI billing exposure), database writes (injection via JSON shape), and Stripe operations (amount tampering).

    The fourth is the npm dependency tree itself. Recent supply-chain incidents documented in The Hacker News reporting on a malicious npm package using a hidden prompt show a pattern in which a typosquatted package (in that case, eslint-plugin-unicorn-ts-2) ships a post-install script that exfiltrates environment variables to a webhook. The package included a fragment of text aimed at deflecting AI security scanners. By the time it was flagged, it had been downloaded close to nineteen thousand times. A Bolt.new project that runs npm install without further audit picks up whatever the AI chose, including any cousin of that pattern.

    The fifth is the absence of security headers. The deployed bundle ships without a Content Security Policy, without X-Frame-Options, and without Strict-Transport-Security. These do not block exploitation by themselves, but their absence widens the attack surface.

    How do I audit the npm dependency tree of a Bolt.new project?

    The honest answer is that no single command audits a dependency tree for malicious packages. The npm audit command reports known CVEs against the registry's advisory database. That is necessary, not sufficient. A practical audit combines several passes.

    The starting point is npm ci, run from the lockfile, in a clean checkout. The OWASP NPM Security Cheat Sheet explains why this matters: npm install will resolve fresh versions; npm ci installs exactly what the lockfile records. For an audit, you want a frozen, reproducible tree.

    The next pass is npm audit --omit=dev for the production tree and a separate npm audit for the full tree. Reading both outputs gives a picture of where vulnerable code lives. If a known vulnerability sits only in devDependencies, the user-facing build is unaffected; the build pipeline still warrants attention.

    A third pass the OWASP cheat sheet recommends is to set ignore-scripts=true in .npmrc. Post-install scripts are the most common malicious payload vector. Disabling them by default and using an explicit allowlist (such as @lavamoat/allow-scripts) for the small number of packages that genuinely require build steps removes a class of attacks the audit command cannot see.

    A fourth pass is to verify each direct dependency by hand. The npm view <package> command shows the publisher, the publish date, the maintainers, and the linked repository. A new dependency published last week, with no GitHub repository, and a name that almost matches a popular package, is the typosquat shape.

    For the dependency tree of a typical Bolt.new project, the time cost of the four passes is in the order of one to two hours and pays for itself the first time it catches a problem package.

    What does a real pre-ship Bolt.new security checklist look like?

    The five-gate pre-submission model (Permissions, SDKs, Storage, Network, Build) adapts cleanly to Bolt.new. Each gate is a yes or no question the developer answers before deploying.

    GateQuestionBolt.new defaultProduction-ready
    PermissionsDoes any client call a paid API directly?Yes, via Vite env varNo, proxied through a serverless function
    SDKsHas every direct dependency been verified with npm view?NoYes, publisher and repo confirmed
    StorageDoes every Supabase table have an RLS policy?No (RLS off)Yes (RLS on, policies per role)
    NetworkDoes the deployed app send CSP, HSTS, and frame-ancestors headers?NoYes (set at the host or proxy)
    BuildDoes the deployed bundle contain source maps or .env strings?Often yesNo (source maps excluded, env audited)

    The table is not exhaustive. It is the minimum surface a developer can carry in their head while shipping. PTKD.com (https://ptkd.com) is one of the platforms focused on running this kind of pre-submission scan on AI-coded builds, including bundles produced by Bolt.new, against OWASP MASVS-aligned controls before the deploy goes live. For solo developers without a security review process, an external scan is the practical substitute.

    What to watch out for

    • A passing npm audit is not a clean dependency tree. It only reports catalogued CVEs. Recent malicious packages routinely slip past it.
    • A Vite environment variable prefixed VITE_ is public. The Vite documentation states this explicitly; review every .env line before deploy.
    • A Supabase anon key in the client is normal, but only with RLS. Without RLS policies, the anon key allows full table access to any visitor.
    • Deploying a hot-fix commit straight from the AI is the highest-risk pattern. Bolt.new will happily generate new code that bypasses the safety changes a developer already added. Each prompt is a new audit surface.
    • A serverless function with no authentication is a public endpoint. Treat it as such when wiring AI or payment calls behind it.

    Key takeaways

    • Bolt.new generated code is a real codebase, not a sandbox. Treat the audit surface the same as a hand-written project.
    • The recurring failure pattern is keys in client bundles, RLS off, no input validation, and an unaudited npm tree. Fixing those four removes most of the practical risk.
    • The dependency tree deserves a manual pass. The npm audit command catches CVEs; npm view and ignore-scripts=true catch the rest.
    • Some teams outsource the pre-ship scan to a platform like PTKD.com (https://ptkd.com). For solo developers shipping AI-coded apps to a real user base, an external scan against OWASP MASVS-aligned controls is a calm alternative to building an in-house review.
    • Production-ready is a checklist, not a setting. Bolt.new gets you to a running app. The remaining gap is the audit you run before the first real user lands on it.
    • #bolt-new
    • #ai-coded-apps
    • #npm-security
    • #supabase
    • #vibe-coding
    • #pre-submit-audit
    • #supply-chain

    Frequently asked questions

    Can I use npm audit alone to clear a Bolt.new project for production?
    No. The npm audit command checks the registry's advisory database for known vulnerabilities, which is necessary but not sufficient. Recently published malicious packages, including typosquats designed to mimic popular names, often clear npm audit because no advisory exists yet. A real audit also reviews each direct dependency with npm view, disables post-install scripts by default in .npmrc, and inspects the publisher and linked repository for any package that looks unfamiliar.
    What is the single most common Bolt.new security issue developers report?
    API keys exposed in the client bundle. Anything prefixed VITE_ in a Vite project ends up in the published JavaScript by design, so a Stripe secret key or OpenAI key placed there is public the moment the site deploys. The fix is to put paid-API keys behind a serverless function and pass only public-tier anon keys (such as Supabase's anon key, paired with Row Level Security) to the browser.
    Is Bolt.new safe for handling user payments through Stripe?
    Not at the default settings. Bolt.new commonly wires Stripe calls directly from client code with the secret key in an environment variable. That key ends up in the bundle and can be extracted by any visitor. A production-ready setup keeps the Stripe secret server-side, exposes only the publishable key to the browser, validates the amount on the server, and uses Stripe webhooks to confirm the charge before granting any entitlement.
    How do I tell if a Bolt.new project has Supabase Row Level Security enabled?
    Open the Supabase dashboard, go to the Table Editor, and inspect each public table. The RLS toggle sits at the top of the table view, and the Policies tab lists every active rule. A table with RLS off, or RLS on with zero policies, is fully readable by anyone holding the anon key, which the deployed Bolt.new app is shipping to the browser. The fix is to write at least one policy per role, then enable RLS.
    Does the eversudoku case mean every Bolt.new app is broken?
    No. Eversudoku is one publicly discussed example, not a verdict on the platform. Bolt.new generates a real codebase, and a real codebase can be audited and fixed. The lesson from any specific case is the same as for hand-written projects: review the dependency tree, check the database storage rules, and confirm that no secret keys ship inside the bundle. A working Bolt.new app and a production-ready Bolt.new app are two different artifacts.

    Keep reading

    Scan your app in minutes

    Upload an APK, AAB, or IPA. PTKD returns an OWASP-aligned report with copy-paste fixes.

    Try PTKD free