Clerk published GHSA-vqx2-fgx2-5wq9 on April 24, 2026, disclosing CVE-2026-41248, an interpretation-conflict bug in createRouteMatcher — the helper that backs middleware-based route protection in @clerk/nextjs, @clerk/nuxt, and @clerk/astro. Specially crafted requests can trick the matcher into deciding a protected route is not protected, dropping straight through clerkMiddleware() and into the downstream handler without any auth gate firing.
Anyone shipping a Next.js, Nuxt, or Astro app that leans on createRouteMatcher to fence off /admin, /dashboard, billing endpoints, or internal APIs needs to be on a patched SDK before the working day starts.
What broke
createRouteMatcher takes a list of route patterns and returns a function that, given an incoming request, answers “is this one of the protected routes?” Most Clerk-on-Next.js codebases follow the canonical pattern: a middleware.ts builds an isProtectedRoute = createRouteMatcher([...]), and inside clerkMiddleware() the auth check is conditional on that match. If the matcher returns false, the middleware lets the request through unauthenticated.
The advisory categorises the bug as CWE-436 (Interpretation Conflict) and CWE-863 (Incorrect Authorization). In plain terms: the matcher and the framework’s router parse the same URL into different shapes. A request can be normalised one way for the matcher (which sees a path that doesn’t match any protected pattern) and a different way for the route resolver (which happily dispatches it to a protected handler). Clerk’s notes are explicit that the issue lives in path normalisation and routing logic, not in session validation — existing sessions and cookies are not forgeable, and no existing user is impersonated. What is bypassed is the gating decision itself.
The practical consequence depends entirely on whether the downstream handler does its own auth check. Apps that treat the middleware match as sufficient — and many do, because that’s the documented Clerk pattern — are reachable by an unauthenticated attacker.
Affected and patched versions
The vulnerability is fixed across three major version branches per SDK, so most teams will be picking up a minor or patch bump rather than a breaking upgrade:
@clerk/nextjs: 5.7.6, 6.39.2, 7.2.1@clerk/nuxt: 1.13.28, 2.2.2@clerk/astro: 1.5.7, 2.17.10, 3.0.15@clerk/shared(transitive dependency carrying the matcher): 2.22.1, 3.47.4, 4.8.1
Per the GitLab advisory, the affected ranges in @clerk/shared cover everything from 2.20.17 up to the patched releases, and similar windows reach back through the canary builds in the 3.x line. If your lockfile shows a @clerk/shared older than 2.22.1 / 3.47.4 / 4.8.1, the vendored SDK above it is exposed regardless of which framework wrapper you imported.
Detection
There is no IOC list to grep for — the exploit is a malformed URL, not an artifact left on disk. Two checks are useful right now.
First, dump your lockfile and confirm the resolved versions of @clerk/nextjs (or nuxt / astro) and @clerk/shared. Indirect dependencies matter; a workspace where one app pinned an older @clerk/shared will keep that vulnerable copy even after the framework wrapper is upgraded.
| |
Second, look at access logs for the routes you’ve put behind createRouteMatcher. Unauthenticated 200s on protected paths — especially with unusual percent-encoding, doubled slashes, trailing dots, or path-traversal sequences in the request line — are the shape of an attempted bypass. The exact gadget hasn’t been published, but interpretation-conflict bugs almost always live in encoding or normalisation edge cases, so anomalous URL shapes against gated routes are the right thing to alert on.
Mitigation
Upgrade. The fix is in the matcher itself; there is no configuration toggle that closes this without code changes. After the upgrade, re-deploy the affected service and invalidate any cached build artifacts that bundled the old @clerk/shared.
While you are in that code, this is a good moment to add belt-and-braces auth checks at the route handler level for anything sensitive — admin pages, billing endpoints, anything that reads or mutates other users’ data. Treating middleware as the only gate has been a recurring pattern of failure across frameworks: it was CVE-2025-29927 in Next.js itself last year, and it is this CVE in Clerk now. Defence in depth — auth().protect() inside the page or getAuth() inside the API handler — turns a future matcher bypass into a non-event.
Why this matters
Clerk sits behind a meaningful slice of production Next.js, Nuxt, and Astro apps, and createRouteMatcher is the documented pattern for guarding routes. A bypass in that helper is a bypass in the threat model most of those apps were built to. The blast radius is wide, the patch is small, and the fix is sitting in npm right now. The work is finding every service in your fleet that pulls Clerk in transitively and getting them all onto a fixed @clerk/shared before someone publishes the gadget.
Sources:
- GHSA-vqx2-fgx2-5wq9 — Official Clerk JavaScript SDKs: Middleware-based route protection bypass (GitLab Advisory Database)
- CVE-2026-41248 — Vulnerability-Lookup (CIRCL)
- CVE-2026-41248 — OffSeq Threat Radar
- CVE-2026-41248 — THREATINT
- Clerk Astro SDK advisory (GitLab)
- CVE-2025-29927 — Authorization Bypass in Next.js Middleware (GitHub Advisory)