The risk is a known-vulnerable package you never chose
Before you share the URL, the concrete risk is this: your Vite or Next.js app ships with one or more npm packages that have a published advisory, and you do not know it. The advisory is public, indexed in the GitHub Advisory Database (GHSA), and it names the exact package and version range. Anyone can read it, including someone deciding whether your app is worth probing.
This is observable, not hypothetical. A package with a known issue is either in your dependency tree at a vulnerable version or it is not, and one command answers that. What is not observable from the advisory alone is whether the vulnerable code path is reachable in your app. A flaw in a server-side parser matters very differently from a flaw in a build-time tool that never runs in production. So the count from a scan is the start of a decision, not the decision itself.
A vulnerable npm package in a Vite or Next.js production build splits into two questions you have to keep separate. First, is the advisory real and does it touch a version you actually ship. Second, does it sit in code that runs where an attacker can reach it, or only in tooling that ran on your machine at build time. Conflating those two is how people both panic over harmless warnings and wave through ones that matter.
Why AI-built apps carry more of these
An AI builder optimizes for an app that runs, fast. It reaches for whatever package solves the immediate prompt, and it rarely prunes. The result is a dependency tree that is wide and deep, with dozens to hundreds of transitive packages you never named and never reviewed.
None of this means the app is exploitable. It means the surface of "packages that could carry an advisory" is larger than you picked, so checking it deliberately is worth the few minutes before launch.
- The generated package.json lists a handful of direct dependencies, but each pulls its own subtree. Most known-vulnerable packages you will find are transitive, several layers down, not anything you typed.
- AI tools tend to pin loose version ranges or omit version discipline, so a fresh install can resolve to whatever the registry serves that day. Without a committed lockfile the tree you tested is not guaranteed to be the tree you deploy.
- The review loop that a human team applies, where someone asks "do we actually need this package," does not happen in a one-prompt build. Nothing trims the tree, so abandoned or superseded packages linger.
- Vite and Next.js both bundle and transform code through a large build toolchain. Many advisories you will see touch that toolchain, not your runtime, which is exactly why the devDependency-versus-runtime distinction matters here.
Run the scan on your own tree
These are self-checks on your own project. Run them from the project root, on the same lockfile you intend to deploy.
The baseline is npm audit. It reads your installed tree and your lockfile, compares it against the advisory database, and prints what it finds with a severity per advisory. Run it for npm projects, pnpm audit for pnpm, and yarn audit for Yarn. For Next.js this covers both your app dependencies and the framework's own subtree; for a Vite SPA it covers the build toolchain plus whatever runtime libraries you bundle.
Next, separate the noise. Run npm audit --omit=dev (or the equivalent --production flag your version supports) to see only what ships at runtime. A finding that disappears when you omit dev dependencies is in your build or test toolchain, and a build-time package that never runs in production is hardening, not a launch blocker. A tool like better-npm-audit helps here by letting you record an allowlist of advisory IDs you have triaged, so the next run only shows new findings instead of the same noise.
- Safe result: npm audit reports zero vulnerabilities, or only findings in devDependencies that you confirm never ship to the browser or server runtime.
- Suspicious result: a high or critical advisory on a package that runs in production, for example a server-side dependency in a Next.js API route or a runtime library bundled into your Vite output.
- Read each finding by its GHSA identifier, not just its color. The advisory page states the affected versions, whether a patched version exists, and often whether exploitation needs specific input or configuration.
- Check whether the package runs server-side, client-side, or only at build time. That single fact reorders the whole list.
- For a deeper read on translating audit output into a go or no-go, see npm audit before launch: what the output actually means, and for the broader stale-dependency decision see outdated dependencies as a launch blocker.
Fix what ships, and know the limits
The cleanest fix is to move to a patched version. Run npm audit fix to apply non-breaking upgrades automatically. Re-run the audit afterward and confirm the count actually dropped, because "fix" only resolves what it can resolve without changing a major version.
What this does not cover: an audit finds known advisories only. It says nothing about a package that is malicious but not yet reported, a typosquatted or hallucinated package name an AI tool suggested, or a hardcoded secret sitting in your own source. Those are separate checks. For secrets that an AI tool baked into your code, see hardcoded secrets in AI-generated code. The audit also cannot tell you whether a flagged code path is reachable in your specific app; that judgment is yours, informed by where the package runs.
- For transitive packages with no direct upgrade path, an npm overrides block (or pnpm overrides, or Yarn resolutions) can force a patched version of a sub-dependency. Test the app after, since you are pinning a version the parent did not request.
- Avoid npm audit fix --force unless you have read what it does. It will install breaking major versions to clear advisories, and it can break your build or runtime. On a launch-day timeline a broken build is a worse outcome than a triaged, deferred devDependency advisory.
- For a runtime advisory with no patch available, the honest options are to remove or replace the package, or to accept the risk explicitly with a note on why the code path is not reachable. Do not silently ignore it.
npm audit answers "do I ship a version with a published advisory." It does not answer "is my app exploitable." A zero-finding audit is a clean dependency snapshot for today, not proof the app is secure, and tomorrow's advisory can change the count without you touching the code. Re-run it before each release.
Where VibeCodeGuard fits
This dependency audit is a pre-deploy gate you run locally, against your own tree and lockfile. VibeCodeGuard's Launch Check works on the other side of the deploy: it scans the public URL for the signals an outside visitor can see, including security headers, exposed source maps, leaked build or deploy artifacts, and secret-shaped strings in the client bundle. It does not read your package.json, run npm audit, or evaluate GHSA advisories, because those live in your repo, not on the public surface.
So the two complement each other rather than overlap. The local audit catches known-vulnerable packages before they ship; the Launch Check confirms what the deployed app actually exposes once it is live. Running the audit does not replace the public-surface scan, and the public-surface scan does not replace the audit.
Next step: run npm audit (or pnpm audit) on your project now, omit dev dependencies to see what truly ships, and resolve any runtime high or critical findings before you deploy. Then run a focused Launch Check against the public URL before sharing it, so the deployed surface is covered too.
A clean Launch Check does not mean your dependencies are clean, and a clean npm audit does not mean your public surface is safe. They look at different layers. Treat each as one signal.
> launch check
Scan the public surface before launch.
Get severity, evidence, and practical fix guidance for the checks VibeCodeGuard can run from the outside.