Quick Answer
VibeDoctor runs a scanning pipeline built specifically for AI-generated applications: Lighthouse performance analysis, SSL and security header checks, secret detection with Gitleaks, CVE scanning with Trivy, language linters for code quality, custom project hygiene checks, and a Vibe Checks scanner for AI-specific patterns.
What VibeDoctor Actually Scans
Most security tools scan one thing: your source code, or your dependencies, or your live site. VibeDoctor scans all three simultaneously because production readiness is not a single-dimension problem. An app can have clean code but a broken deployment. It can have secure authentication but an expired SSL certificate. It can have no CVEs in its dependencies but a Lighthouse performance score of 24.
The VibeDoctor scanning pipeline runs two parallel workflows the moment you submit your app:
The live site pipeline launches a real Chromium browser and visits your deployed URL. It runs Google Lighthouse to measure performance, accessibility, SEO scores, and Core Web Vitals. It checks your SSL certificate for validity, expiry, and protocol version. It requests your page and checks the six key security response headers (HSTS, CSP, X-Frame-Options, X-Content-Type-Options, Referrer-Policy and Permissions-Policy), plus cookie flags and server version leaks. It detects JavaScript runtime errors and console exceptions. It crawls internal links to find broken 404s. It measures total page weight, request count, and mixed HTTP/HTTPS content.
The code pipeline clones your repository (or uses uploaded source) and runs a battery of scanners in parallel: Gitleaks checks every file for committed secrets, API keys, and credentials; Trivy checks the dependencies in your lockfiles against public vulnerability databases for known CVEs; OpenGrep runs security rules across the codebase; Biome, ruff, pyright, golangci-lint, clippy, RuboCop, PHPStan and tsc run static analysis for each language in the repo; a package verifier checks every import against the live npm and PyPI registries to catch hallucinated packages; custom hygiene checks verify the presence of a .gitignore, README, test directory, and absence of a committed .env file; the Vibe Checks scanner runs 40+ checks across security, dependencies, code quality, configuration, frontend, testing, and performance categories.
All findings are normalized into a unified severity taxonomy, scored, and presented in a single report with an overall health grade, section scores, and findings organized by priority.
The Early Numbers
VibeDoctor's own scans give a first picture. The figures below come from 963 codebases scanned between 31 July and 14 October 2026, and from the 336 projects connected to a VibeDoctor account, as of each project's latest scan. The full breakdowns are in our posts on dependency CVEs and leaked secrets.
| Metric | Result |
|---|---|
| Codebases with at least one dependency with a known CVE (of 963) | 654 (67.9%) |
| Codebases with at least one string that looked like a secret (of 963) | 364 (37.8%) |
| Account projects with at least one critical or high CVE (of 336) | 59 (17.6%) |
| Account projects with a real private key or live-format secret key in their current files (of 336) | 19 (5.7%) |
These are real codebases, not lab samples. A known CVE or a leaked key in a live app is not a theoretical concern. It is an active risk for the business behind it and for its users.
A Common Finding: Unprotected API Routes
A common serious finding is unprotected API routes: endpoints that handle user data, payments, or administrative functions with no authentication check. VibeDoctor rates them High when the route changes data.
AI tools generate routes that look correct. They import authentication libraries, reference session tokens, and call methods like getSession(). But sometimes the generated code calls the auth function without checking the return value:
// What AI generates - looks authenticated, is not
export async function DELETE(req: Request, { params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const session = await getSession(req); // called but not checked
await db.delete(items).where(eq(items.id, id));
return Response.json({ deleted: true });
}
// What it should look like
export async function DELETE(req: Request, { params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const session = await getSession(req);
if (!session?.user) {
return Response.json({ error: 'Unauthorized' }, { status: 401 });
}
// Verify the user owns this item before deleting
const item = await db.query.items.findFirst({
where: and(eq(items.id, id), eq(items.userId, session.user.id))
});
if (!item) return Response.json({ error: 'Not found' }, { status: 404 });
await db.delete(items).where(eq(items.id, id));
return Response.json({ deleted: true });
}
This is not a subtle vulnerability. Any attacker who discovers the endpoint can delete, modify, or read any record in the database without authenticating. But it is extremely easy for a non-engineer reviewing AI-generated code to miss, because the authentication call is present. The absence of the check is the problem, and absence is always harder to notice than presence.
Another Common Finding: Client-Side Secret Exposure
Secrets committed to source code or exposed via NEXT_PUBLIC_ prefixed environment variables are another common Critical finding. The mechanism is subtle and AI tools fall into it consistently:
# In .env.local - AI-generated by Bolt or Lovable
NEXT_PUBLIC_SUPABASE_URL=https://xxx.supabase.co
NEXT_PUBLIC_SUPABASE_ANON_KEY=eyJhbGci... # This one is fine
NEXT_PUBLIC_SUPABASE_SERVICE_ROLE_KEY=eyJhbGci... # This one is CRITICAL
NEXT_PUBLIC_OPENAI_API_KEY=sk-... # This exposes your billing account to the entire internet
NEXT_PUBLIC_STRIPE_SECRET_KEY=sk_live_... # Anyone can now create charges on your account
The NEXT_PUBLIC_ prefix tells Next.js to include the variable in the browser bundle. Every user who visits your site can extract these values from the JavaScript that loads in their browser. Attackers scan GitHub repositories and Vercel deployments for exactly these patterns.
Also Common: Missing Security Headers
Many scanned apps ship without the key security response headers: no Content-Security-Policy, no X-Frame-Options, no Permissions-Policy. Vercel and Netlify send HSTS by default, but they do not add the others for you, and AI tools rarely add them. The result is that many vibe-coded apps are trivially embeddable in iframes for phishing and clickjacking attacks, and have no browser-side defense if an XSS bug slips through.
Adding security headers takes about 20 lines of configuration in next.config.js. The remediation is fast and the protection is significant. But the headers are completely invisible to anyone who does not know to look for them, which is why so many apps ship without them.
Performance: The Other Half of the Problem
Security findings get the most attention, but performance is the other dimension where AI-generated apps often underperform, and Lighthouse makes it visible on every URL scan.
The core reasons are structural to how AI tools generate apps:
- Bundle size is not optimized. AI tools import full libraries when only specific functions are needed. Pulling in all of Lodash, Moment.js, or similar large utilities without tree-shaking can add tens to hundreds of kilobytes to the JavaScript bundle.
- Images are not optimized. AI tools generate
<img>tags, not Next.js<Image>components. Large uncompressed images load without lazy loading or responsive sizing. - No code splitting. The entire application loads on the initial page request rather than splitting code by route and loading it on demand.
Lighthouse rates a performance score below 50 as poor, and Google's 2016 research found that 53% of mobile visits are abandoned when a page takes longer than 3 seconds to load. For a commercial app trying to convert visitors, this is a significant revenue impact, not just a technical metric.
What Happens After a Scan
VibeDoctor does not just identify problems. Each finding in the report comes with a plain-English explanation of why it matters and what to change, and on paid plans a fix prompt you can paste into your AI coding tool. The findings are organized by severity so users know exactly where to start.
The Critical findings (secrets, exposed environment variables, SQL injection) are usually the fastest to fix, because the remediation is specific: rotate the key, move it server-side, parameterize the query. Re-scan afterwards to confirm the finding is gone.
How to Run Your Scan
Visit vibedoctor.io and enter your deployed URL or connect your GitHub repository. No credit card, no configuration files, no CI pipeline setup. The scan runs in minutes and delivers a scored report covering all the categories above. The Free Week includes a full scan with no limitations on findings or sections. Sign up, scan your app, fix what it finds.
FAQ
What counts as a Critical finding in VibeDoctor?
Critical findings are issues that, if exploited, could result in unauthorized access to user data, financial accounts, or system infrastructure. Examples include hardcoded API keys, secrets exposed through NEXT_PUBLIC_ variables, a committed .env file that holds a real secret, and SQL injection vulnerabilities. Unprotected routes that change data are rated High. These are issues that require immediate remediation before deployment.
How long does a scan take?
Most scans finish in a few minutes, depending on the size of the codebase and the response time of the deployed URL. The live site and code pipelines run in parallel to minimize total scan time. Large repositories can take longer.
Does VibeDoctor scan apps built with Supabase?
Yes. A Supabase service_role key committed in a .env file is flagged as critical, and secret scanning catches keys hardcoded in source. VibeDoctor does not inspect your Row Level Security policies or Edge Functions, so review those in the Supabase dashboard.
Can I re-scan after fixing issues?
Yes. Re-scanning after fixing findings is encouraged and shows your score improvement over time. Paid plans also re-scan your code automatically after every push to your main branch, so you always know your current security posture.
Are the numbers in this article based on VibeDoctor's own scan data?
Yes. They come from VibeDoctor's own scans: 963 codebases scanned between 31 July and 14 October 2026, including free scans of public repositories, and the 336 projects connected to a VibeDoctor account, as of each project's latest scan. No project or owner is identified.