50 sites, 444 findings: the 2026 state of shipping-fast security
There are roughly two ways a web app ships in April 2026.
The first is "vibe-coded": a developer — sometimes not a developer at all — types a prompt into Lovable, Bolt, v0, Cursor, or Claude Code, and a Next.js app lands on Vercel 40 minutes later with a working Supabase backend. The second is the long tail: a five-year-old WordPress site on cheap shared hosting that has not been touched since someone's nephew built it. Both are real. Both are in our scan queue every day.
We took 50 production URLs covering both cohorts plus a handful of cloud-platform and auth-SaaS homepages, pointed our engine at them, and wrote down exactly what came back. The numbers below are real. We are not naming sites — the patterns matter more than the brands, and responsible disclosure matters more than clickbait.
The numbers
On the 41 sites that scored: 88% SHIP, 12% BLOCK. Average score 65.6, median 76. Lowest 0, highest 98. Every single site had findings — the cleanest had 2, the worst had 24, mean was 10.8 per scan.
| Grade (auto-computed from score) | Sites | Share of scored |
|---|---|---|
| A (90–100) | 5 | 12% |
| B (75–89) | 16 | 39% |
| C (60–74) | 11 | 27% |
| D (40–59) | 4 | 10% |
| F (0–39) — BLOCK | 5 | 12% |
A word on the 9 that didn't score: every one of them bounced the scanner with a WAF challenge (Cloudflare Turnstile, Kasada, or a tenant-specific anti-bot layer). Those are all well-known SaaS domains that have invested heavily in bot protection. The scanner stopped, logged "target unreachable — WAF/anti-bot respected," and emitted no score. We treat that as a positive signal about the target. Sites that can detect and block our scanner are doing real defensive work. We never fabricate a number for a site we cannot see.
Vibe-coded AI-built apps: the surface looks fine, the machinery often does not
About two-thirds of our batch were AI-built developer tools and infrastructure products. These sites are almost uniformly hosted on modern platforms (Vercel, Netlify, AWS edge), use Next.js or Remix, and inherit baseline security headers from the platform. That platform floor is real, and it shows up in the data: average score for this cohort sat above 70, and a clear majority shipped with SHIP verdict.
The failure mode is not missing security headers. It is what happens inside the application once you look past them.
- Client-side keys in production bundles. We consistently flagged API-key-shaped strings in
/_next/static/chunks/*.js. Some are public-by-design (Google Analytics, Algolia search keys), but a non-trivial share of them are AI-provider keys that the developer put into aNEXT_PUBLIC_*variable to "make it work from the frontend." A single leaked OpenAI or Anthropic key, without a spend cap set in the provider dashboard, is a five-figure problem by the second morning. - Source maps in production. Next.js ships source maps by default. Any visitor can recover near-complete original TypeScript from
/_next/static/chunks/*.js.map. Fixable with one line innext.config.ts. Rare to see it set. - Client-side auth guards with no server enforcement. Multiple apps in our batch had routes that
router.push("/login")when a local session check failed, while the underlying API endpoint had no auth middleware at all. Two browser dev-tools clicks bypass this pattern. - Open infrastructure on adjacent ports. Our network provider probes 23 common service ports (Postgres, Redis, Elasticsearch, Docker API, kubelet, etcd, …) and flags any that respond from the public internet. We found a small but real number of these — usually Redis or PostgreSQL left on the default port without a firewall because the deploy template skipped that step.
None of this is new in 2026 as a class of problem — people have been leaking keys in JS bundles for a decade. What is new is the volume. When anyone can ship a Next.js + Supabase app in under an hour without reading a single line of the generated code, the average production app gets further from "somebody checked the security posture" every quarter. The floor is rising (platforms give you HSTS and a reasonable CSP for free). The ceiling of what teams actually verify before hitting deploy is not.
- CRITICAL WordPress brute-force attack chain: admin username + exposed login
- HIGH WordPress user enumeration (slug: ●●●●●●●●)
- HIGH Generic API key in client bundle (value: AIzaSy●●●●●●●●●●●●●)
- MEDIUM WordPress login page publicly accessible (
/wp-login.php→ 200 OK) - MEDIUM WordPress version 6.9.4 disclosed in HTML
- MEDIUM No Content-Security-Policy header
Legacy CMS: "SHIP" can hide a ready-made brute-force target
A smaller share of our batch were small-business WordPress sites deployed on cheap shared hosting. The pattern here is completely different from the vibe-coded cohort, and more sobering.
On one site in particular (anonymized), three things were true simultaneously:
- WordPress version disclosed in the HTML via the default
<meta name="generator">. Anyone can look up CVEs for that specific version. - The admin username was publicly enumerable via the
/?author=1permalink trick — a decade-old WordPress issue. The site redirected/?author=1straight to/author/<real-admin-slug>/, giving away the exact login name. /wp-login.phpwas publicly accessible, with no IP allowlist, no 2FA, no rate limit.
Individually, each of those is a known-but-ignored WordPress default. Together, they are a complete brute-force attack chain with the username already handed to the attacker. Our engine now escalates that combination to a CRITICAL finding with a BLOCK verdict, because calling it "medium severity" would be lying about the practical risk.
This is not a WordPress-hate post. WordPress is fine when you harden it. The point is: these three defaults ship together, and they combine into something an opportunistic script can hit in under a minute. The industry data tracks this exactly — WordPress has topped every "most compromised platform" list for years running, because it is also the long tail of the web, and because the failure modes above are the ones that come for free if you do not go out of your way to close them.
- CRITICAL Unprotected admin endpoint returning user data (path: /api/admin/●●●●●●)
- MEDIUM CSP report-only mode provides zero XSS protection
- MEDIUM Missing CSRF tokens on state-changing endpoints
- MEDIUM Session cookie missing
Secureflag on subdomain (●●●●.example.ai) - MEDIUM Generic API key in client bundle
One thing we caught mid-research
Our WordPress user-enumeration check initially missed a leak on one target that we had caught in earlier scans. Root cause: the host was silently dropping outbound probes from our scanner IP range. We added a third detection path that scrapes /author/<slug>/ references from the main page HTML we already fetched, so the signal survives even when live probes are blocked. Rescan changed that site from 41/SHIP to 1/BLOCK with the full attack chain visible. It is exactly the kind of silent scanner regression that would not have been caught without an adversarial rerun against a known target. We keep a small fixture set precisely for this. You should too.
The three patterns that actually cause incidents in 2026
Three classes of finding account for a disproportionate share of the realistic-risk alerts in our dataset. If you do nothing else after reading this post, do these three things.
- Check every
NEXT_PUBLIC_*variable. AI-provider keys (OpenAI, Anthropic, Google AI) in client bundles are the fastest-moving class of incident we see. One leaked key, no spend cap in the provider dashboard, one opportunistic scraper — that is a four-to-five-figure bill by the next morning. Move the call server-side. Always. - Audit your Supabase RLS and Firebase rules with an actual probe. The dashboard saying "RLS enabled" means the toggle is on. It does not mean your data is protected. A
USING (true)policy returns every row to the anon key that ships in your frontend. A Firestoreallow read, write: if truedoes the same for Firebase. This is the most common class of data leak we see in vibe-coded apps — and it is invisible to any URL-only scanner. - Probe your own database ports from outside your VPC. Redis, PostgreSQL, Elasticsearch, Docker API on 2375, Kubelet on 10250 — every one of these reachable from the public internet is a full compromise waiting for an opportunistic scanner. A small but non-zero fraction of our batch leaked at least one. Every one of those was a template deploy where someone skipped the firewall step.
What 2026 actually changed
Three things are new this year that old security-research posts miss:
- MCP servers are a fresh attack surface. Model Context Protocol servers give LLMs tool-use capabilities. They also expose filesystem reads, shell commands, and API bridges that are often shipped with zero auth because "it's just local." A hostile prompt (via document, web page, or email) can hijack an agent's tool calls through tool-poisoning and exfiltration flows. Our deep scan added MCP-specific checks in Q1 2026; they fire more often than we expected.
- The vibe-coding floor is higher than it was in 2024. Next.js 16 ships stricter CSP defaults. Vercel now sets HSTS by default on new projects. Supabase's 2025 UI nags you about permissive RLS. The baseline improvements are real. It is why our median score of 76 is higher than the 60s we saw a year ago. The ceiling has not moved — apps that wanted to be insecure still manage to be.
- Modern anti-bot is everywhere. 9 of our 50 sites bounced the scanner with Cloudflare Turnstile, Kasada, or a similar challenge. A year ago that number was closer to 2. When your homepage can tell a scraper from a human with zero user friction, a whole class of 2021-era scanner assumptions stop applying. Our engine explicitly respects these blocks — we never guess at a score behind a WAF.
Our conclusions
Security can't be the last step anymore. It has to be a ship requirement. The average app we scan has 11 real findings. Most are low severity. Almost none are fixed in the day or two after we flag them, because nobody owns "fix the blog-post-worthy stuff." Teams that treat security as a gate — a thing that has to pass before the deploy button works — end up with a fraction of the findings of teams that treat it as a periodic audit. We see this in our own rescans: the gap between first scan and third scan, for teams that actually fix things, is roughly 30 points of trust score.
The "vibe-coded" vs "legacy CMS" divide is a red herring. Both produce real incidents. Vibe-coded apps fail at the boundary between client and server — keys in bundles, client-side auth, misconfigured integrations. Legacy CMS apps fail at the platform-default level — exposed login pages, enumerable users, out-of-date versions. Different failure modes, identical outcomes for the user whose data leaks.
Header scanning alone is not enough. Our free tier catches platform misconfiguration — which is real, and which is where ~70% of our findings live. The other 30%, and a much bigger share of the critical ones, only show up with a deep scan: RLS policy audit, Firebase rules audit, active DAST, network port probing, JS deep analysis, MCP server checks. That split is not a marketing construction, it is what the data forces.
Test your scanner — ours included — against a known-vulnerable target. We caught a silent regression in our own WordPress user-enumeration check during this research, only because we knew the expected result from an earlier run. Any scanner can regress. Keep a fixture you re-scan weekly and alert when the number changes. If you do not, you will eventually ship assuming you're protected by something that stopped working months ago.
Methodology
50 URLs submitted, 41 completed, 9 held by WAF. One engine, same rules, same scoring. Scans ran from a single cloud instance, no hand-tuning per target, no manual finding edits. Free scans run 9 of 15 providers; deep scans with credentials run all 15. Every finding is tagged with a severity, a confidence level, and a CWE class. BLOCK is reserved for confirmed criticals, a score below 40, or a compound attack chain.
The full list of what we check is at /docs. The free scan is at /scan. If you want the raw per-site data from this research (with the same redactions we published here), email research@sekrd.com and we'll send the CSV.
We run this research quarterly. The next batch will double the sample size and add scheduled re-scans of the BLOCK cohort, so we can measure which patterns actually get fixed.
Don't ship until you're sekrd
Run a free scan to find the vulnerabilities your AI missed.
Scan Your App Free