Is Your Nuxt Admin Route Actually Protected? (2026 Advisory)

If you have a file called pages/Admin.vue in a Nuxt app, and you protect it with a route rule that runs auth middleware, that rule may have quietly stopped matching. Not for attackers. For everyone. The page rendered, the middleware did not run, and nothing in your logs said so.

That is the substance of a Nuxt advisory published on 2026-07-27, tracked as GHSA-hxvh-4h3w-prp9 and rated High at CVSS 8.2. As of this writing it has no CVE ID assigned.

TL;DR

Nuxt versions 4.4.7 to 4.5.0 and 3.21.7 to 3.21.9 silently drop any route rule whose key contains a capital letter. If you use routeRules with appMiddleware as your authorization gate, and the key has an uppercase character in it, that gate never ran. Capital letters get in by themselves: Nuxt derives rule keys from PascalCase page files like pages/Admin.vue. Fixed in 4.5.1 and 3.21.10. The two-minute check is below.

The two bugs point in opposite directions

This is the part that trips people up, so it is worth getting straight before you check anything.

There were two bugs, and the second is the botched fix for the first.

The original bugThis one
AdvisoryCVE-2026-53721GHSA-hxvh-4h3w-prp9
What went wrongRoute rules matched case-sensitively while the router matched case-insensitivelyThe fix lowercased the lookup path but left the rule keys as written
Who triggers itAn attacker, by flipping the case in the URLNobody. It is broken for every request
SymptomRequesting /Admin/dashboard skipped the rule for /admin/dashboardA rule keyed /Admin never matches anything
Fixed in4.4.7 / 3.21.74.5.1 / 3.21.10

In the original, an attacker had to do something: change the capitalisation of a URL to slip past a rule. Nuxt patched that in 4.4.7 by lowercasing the incoming path before looking up a rule.

The problem is that it only lowercased one side. Rule keys stayed exactly as written. So from 4.4.7 onward, a lowercased lookup path could never equal a key containing a capital letter, and any such rule simply stopped existing as far as the matcher was concerned.

If you read about the first bug and "fixed" it by being careful with capitalisation in your route rules, you may have walked directly into the second one. A rule keyed /Admin is exactly the shape that stopped matching.

The advisory's own description of the cause: the earlier fix "lowercased the lookup path before matching route rules, but the route-rule keys compiled into the matcher were left verbatim. As a result, any route rule whose key contains an uppercase character never matches."

Why you can have this without writing a capital letter

Most people reading this are thinking "I would never key a route rule /Admin." Probably true. It does not matter.

Nuxt uses file-based routing, and it derives route rules from your page filenames. The advisory calls this out by name: the affected keys include "the rules Nuxt derives from PascalCase/camelCase page files such as pages/Admin.vue."

So the sequence that gets you here is entirely ordinary. You name a page component Admin.vue, because that is how Vue components are conventionally named. Nuxt turns that into a route rule key with a capital A in it. Your appMiddleware gate hangs off that key. The key never matches. Your admin page is now ungated, and you never typed anything unusual.

This is worth sitting with if you build with AI tools. Ask Cursor, Claude Code, or Bolt to scaffold a Nuxt admin section and you will get Admin.vue, Dashboard.vue, UserSettings.vue, because PascalCase is the correct convention for Vue single-file components and the model knows that. The convention is right. It just happened to collide with a broken matcher.

The two-minute check

Do this in order. Stop as soon as one of them clears you.

1

Check your version.

Terminal
npx nuxt info | grep -i "nuxt version"
# or
cat node_modules/nuxt/package.json | grep '"version"'

You are only in scope for Nuxt 4.4.7 through 4.5.0, or 3.21.7 through 3.21.9. Anything older than 4.4.7 or 3.21.7 predates the broken fix. Anything at 4.5.1 or 3.21.10 and up is patched. Note that a caret range like "nuxt": "^4.3.1" in package.json tells you what you asked for, not what is installed, so check the resolved version.

2

Check whether you gate anything with route rules.

Terminal
grep -n "appMiddleware" nuxt.config.ts

No results means this advisory does not reach you. Route rules that only set caching, headers, or prerendering are not authorization gates, and a rule that silently fails to apply a cache header is a performance bug, not an open admin panel.

3

Look for capital letters, in both places they can come from.

Terminal
# rule keys you wrote yourself
grep -nE "^\s*['\"]/[^'\"]*[A-Z]" nuxt.config.ts

# page filenames Nuxt will derive keys from
find app/pages pages -name '*[A-Z]*' 2>/dev/null

Anything that comes back from either command, and that you are relying on for access control, is the thing to fix.

We ran this on CheckYourVibe while writing the post, since this site is a Nuxt app. It took about two minutes: our resolved version is below the affected range, we have routeRules but none of them carry appMiddleware, and we have no uppercase page filenames. Three separate reasons to be clear. That is not us saying the bug is rare, it is us saying the check is genuinely quick.

Fixing it

Upgrade. nuxt@4.5.1 or nuxt@3.21.10, both published 2026-07-27.

npm install nuxt@^4.5.1
# or, on the 3.x line
npm install nuxt@^3.21.10

The advisory also lists workarounds if you cannot upgrade immediately:

  • Use lowercase-only route rule keys and page filenames.
  • Turn on case-sensitive routing with router: { options: { sensitive: true } }.
  • Enforce the authorization server-side, independently of route rules.

Upgrading is the fix. The third workaround is the one to keep afterwards.

Upgrading is not the end of it. The advisory explicitly recommends auditing any uppercase route rule keys you use for access control after you patch, because the patch makes those rules start matching again. A rule that has not applied in weeks is about to start applying, and you want to know what it does before it does it.

The part that outlives this advisory

A specific version of a specific framework had a specific matcher bug, and that will be fixed and forgotten. The structural lesson will not be.

Route-level middleware is a single checkpoint, and it sits far away from your data. It answers one question, "is someone logged in," and it answers it based on a string comparison against a URL. Anything that breaks that string comparison, a matcher bug, a trailing slash, a case mismatch, a new route somebody added last Tuesday, silently removes your only gate.

A flowchart. A request from the browser reaches Checkpoint 1, which only establishes who is logged in, then Checkpoint 2, which decides whether this particular post belongs to them. Failing either one refuses the request, while hiding the admin button in the browser stops nothing.
Two checkpoints stand between a request and a row. This advisory removed the first one.Full explanationMermaid source

An app with an ownership check next to its data, or row-level security in the database, degrades differently. When the route rule stops matching, the request still reaches a handler that asks whether this caller may have this record, and the answer is still no. You lose a layer instead of losing the wall.

That is the actual takeaway, and it is why this advisory is worth more than a version bump: it is a live demonstration that a check written in your routing config is a check that can be turned off by someone else's refactor.

The rest of the 2026-07-27 batch

This advisory did not ship alone. Nuxt released 8 GHSAs across 7 listed items that day, patched in the same 4.5.1 and 3.21.10 releases. Two others are worth knowing about:

  • A critical remote code execution in @nuxt/devtools, GHSA-279x-mwfv-vcqv. Development-only, so it does not affect your deployed site, but it does affect your laptop. Patched in @nuxt/devtools 3.3.1.
  • Cross-user payload disclosure on cached pages, GHSA-wm8w-6qjm-cv43, on the 4.x line. If you put cache, swr, or isr route rules on authenticated pages that render user-specific data, one user's rendered data could be served to another.

That last one deserves its own look if you cache anything behind a login. Caching a page that contains somebody's name is how a personalised page becomes everybody's page.

How do I know if my Nuxt app is affected?

Three things all have to be true. You are running Nuxt 4.4.7 to 4.5.0, or 3.21.7 to 3.21.9. You use routeRules with appMiddleware as an authorization gate. And at least one of those rule keys contains a capital letter, either because you wrote it that way or because Nuxt derived it from a PascalCase page file. If any one of those is false, this particular advisory does not apply to you.

I never typed an uppercase route rule. Am I safe?

Not necessarily. The advisory specifically names the rules Nuxt derives from PascalCase and camelCase page files, such as pages/Admin.vue. If you have a page file with a capital letter in its name and you are gating it through route rules, you got an uppercase key without ever writing one.

What version fixes it?

Nuxt 4.5.1 or 3.21.10, both released 2026-07-27. The matcher now case-folds the rule keys the same way it folds the lookup path, so the two are normalised symmetrically. After upgrading, the advisory still recommends auditing any uppercase route rule keys you use for access control.

Can I fix it without upgrading right now?

The advisory lists three workarounds: use lowercase-only route rule keys and page filenames, turn on case-sensitive routing with router: { options: { sensitive: true } }, or enforce the authorization server-side so it does not depend on route rules at all. The third one is the one worth keeping permanently.

Was this the same bug as the earlier Nuxt route rule CVE?

No, and the direction is opposite, which is what makes it confusing. The earlier bug (CVE-2026-53721) let an attacker flip the case of a URL segment to dodge a rule. This one is the incomplete fix for that: it lowercased the lookup path but left the rule keys alone, so a rule with a capital letter in its key stopped matching anything at all, for every visitor, with no attacker involved.

Is anything answering that shouldn't be?

A scan requests your routes from outside, signed in as nobody, and reports what comes back. 60 seconds, no signup.

Vulnerability Guides

Is Your Nuxt Admin Route Actually Protected? (2026 Advisory)