Skip to content

fix: harden SSR cache guard against case-sensitivity bypass (CVE-2026-53721)#56

Closed
frederikprijck wants to merge 1 commit into
issue-52from
fix/route-rule-case-sensitivity
Closed

fix: harden SSR cache guard against case-sensitivity bypass (CVE-2026-53721)#56
frederikprijck wants to merge 1 commit into
issue-52from
fix/route-rule-case-sensitivity

Conversation

@frederikprijck

Copy link
Copy Markdown
Member

Summary

The #52 cache guard reads route rules via getRouteRules to decide whether to write the authenticated user into the SSR payload. Nitro's route-rule matcher is case-sensitive, but vue-router matches routes case-insensitively — so a mixed-case request (e.g. /Cacheable) renders the /cacheable page while resolving no route rule. The guard therefore doesn't fire, and the user is written into SSR HTML the consumer marked Cache-Control: public, s-maxage. This is CVE-2026-53721.

Confirmed live in this repo (reproduced before the fix): /Cacheable returns the user's sub/email in the raw SSR HTML; /cacheable does not.

Why patched Nuxt doesn't cover us

Nuxt's fix (4.4.7 / 3.21.7) lowercases the path only in its app-level matcher and a nitro-server integration. The nitropack/runtime getRouteRules that this middleware uses is a different code path the patch does not touch, so the bypass still reproduces on patched Nuxt (verified on 4.4.8).

Fix

After checking the request path as-is, re-resolve route rules for the lowercased path (via a synthetic event with a fresh context so getRouteRules recomputes rather than returning the cached result) and skip the write if either is shared-cacheable. Skipping is always fail-safe — the client hydrates the user.

Tests

  • Unit: a shared-cacheable rule reachable only via the lowercased path still skips the write.
  • e2e (caching.test.ts): /Cacheable renders anonymous SSR HTML (it leaked before the fix).
  • Full unit suite (65) + lint + build green.

Scope / base

Based on issue-52 because it hardens that branch's cache guard directly. The same fix (extended to cover the auth0.ssrUser opt-out) is also part of #55; this PR ensures the core #52 guard is protected independently of #55's merge timing.

Note: this guard is best-effort by design — it cannot detect caching set imperatively (setHeader) or by an external CDN. That limitation is documented separately; the robust posture for shared-cache apps is the global opt-out + per-route opt-in (#55).

CVE-2026-53721)

Nitro's route-rule matcher is case-sensitive, but vue-router matches routes
case-insensitively. A mixed-case request (e.g. /Cacheable) therefore renders
the /cacheable page while resolving NO route rule — bypassing the
shared-cacheable cache guard and writing the authenticated user into SSR HTML
that the consumer marked publicly cacheable.

Nuxt's own fix (4.4.7 / 3.21.7) lowercases the path only in the app-level and
nitro-server matchers; the 'nitropack/runtime' getRouteRules path this
middleware uses is not covered, so the bypass still reproduces on patched Nuxt.

Harden in our own code: after checking the request path as-is, re-resolve the
route rules for the lowercased path (via a synthetic event with a fresh context
so getRouteRules recomputes) and skip the write if either is shared-cacheable.
Skipping is always fail-safe — the client hydrates the user.

- middleware: dual lookup (request path + lowercased path)
- unit test: shared-cacheable bypass via casing skips the write
- e2e: /Cacheable renders anonymous SSR HTML (leaked before the fix)
@coderabbitai

coderabbitai Bot commented Jun 23, 2026

Copy link
Copy Markdown

Important

Review skipped

Auto reviews are disabled on base/target branches other than the default branch.

Please check the settings in the CodeRabbit UI or the .coderabbit.yaml file in this repository. To trigger a single review, invoke the @coderabbitai review command.

⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: c53d009d-69ba-4ee0-b11b-3a04f3e01537

You can disable this status message by setting the reviews.review_status to false in the CodeRabbit configuration file.

Use the checkbox below for a quick retry:

  • 🔍 Trigger review
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch fix/route-rule-case-sensitivity

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@frederikprijck

Copy link
Copy Markdown
Member Author

Closing — this fix belongs as a commit directly on the issue-52 branch, not a separate PR. Folding it in there.

@frederikprijck frederikprijck deleted the fix/route-rule-case-sensitivity branch June 23, 2026 11:26
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant