CVE-2025-64765: Astro middleware authentication checks based on url.pathname can be bypassed via url encoded values

Published Nov 19, 2025
·
Updated

A mismatch exists between how Astro normalizes request paths for routing/rendering and how the application’s middleware reads the path for validation checks. Astro internally applies decodeURI() to determine which route to render, while the middleware uses context.url.pathname without applying the same normalization (decodeURI).

This discrepancy may allow attackers to reach protected routes (e.g., /admin) using encoded path variants that pass routing but bypass validation checks.

https://github.com/withastro/astro/blob/ebc4b1cde82c76076d5d673b5b70f94be2c066f3/packages/astro/src/vite-plugin-astro-server/request.ts#L40-L44

js / The main logic to route dev server requests to pages in Astro. / export async function handleRequest({ pipeline, routesList, controller, incomingRequest, incomingResponse, }: HandleRequest) { const { config, loader } = pipeline; const origin = ${loader.isHttps() ? 'https' : 'http'}://${ incomingRequest.headers[':authority'] ?? incomingRequest.headers.host };

const url = new URL(origin + incomingRequest.url); let pathname: string; if (config.trailingSlash === 'never' && !incomingRequest.url) { pathname = ''; } else { // We already have a middleware that checks if there's an incoming URL that has invalid URI, so it's safe // to not handle the error: packages/astro/src/vite-plugin-astro-server/base.ts pathname = decodeURI(url.pathname); // here this url is for routing/rendering }

// Add config.base back to url before passing it to SSR url.pathname = removeTrailingForwardSlash(config.base) + url.pathname; // this is used for middleware context

Consider an application having the following middleware code:

js import { defineMiddleware } from "astro/middleware";

export const onRequest = defineMiddleware(async (context, next) => { const isAuthed = false; // simulate no auth if (context.url.pathname === "/admin" && !isAuthed) { return context.redirect("/"); } return next(); });

context.url.pathname is validated , if it's equal to /admin the isAuthed property must be true for the next() method to be called. The same example can be found in the official docs https://docs.astro.build/en/guides/authentication/

context.url.pathname returns the raw version which is /%61admin while pathname which is used for routing/rendering /admin, this creates a path normalization mismatch.

By sending the following request, it's possible to bypass the middleware check

GET /%61dmin HTTP/1.1 Host: localhost:3000

<img width="1920" height="1025" alt="image" src="https://github.com/user-attachments/assets/7e0eeecd-607a-4c73-b12e-5977a30c9bc4" />

Remediation

Ensure middleware context has the same normalized pathname value that Astro uses internally, because any difference could allow it to bypass such checks. In short maybe something like this

diff pathname = decodeURI(url.pathname); }

// Add config.base back to url before passing it to SSR - url.pathname = removeTrailingForwardSlash(config.base) + url.pathname; + url.pathname = removeTrailingForwardSlash(config.base) + decodeURI(url.pathname);

Thank you, let @Sudistark know if any more info is needed. Happy to help :)

Other sources

Astro is a web framework. Prior to version 5.15.8, a mismatch exists between how Astro normalizes request paths for routing/rendering and how the application’s middleware reads the path for validation checks. Astro internally applies decodeURI() to determine which route to render, while the middleware uses context.url.pathname without applying the same normalization (decodeURI). This discrepancy may allow attackers to reach protected routes using encoded path variants that pass routing but bypass validation checks. This issue has been patched in version 5.15.8.

MITRE

Affected Software

3 affected componentsFixes available
astro Astro<5.15.8
npm/astro<5.15.8
5.15.8
astro Astro Node.js<5.15.8

Event History

Nov 19, 2025
CVE Published
via MITRE·04:41 PM
Data Sourced
via MITRE·04:41 PM
DescriptionWeakness
Data Sourced
via NVD·05:15 PM
RemedyDescriptionSeverityWeaknessAffected Software
Advisory Published
via GitHub·08:03 PM
Data Sourced
via GitHub·08:03 PM
DescriptionWeaknessAffected Software
Free Weekly Intel

Don't miss critical vulnerabilities

Join thousands of security professionals who receive our weekly digest of trending CVEs, zero-days, and exploited vulnerabilities.

No spam. Unsubscribe anytime.

Frequently Asked Questions

1

What is the severity of CVE-2025-64765?

CVE-2025-64765 is categorized as a high severity vulnerability due to its potential impact on routing and request processing.

2

How do I fix CVE-2025-64765?

To resolve CVE-2025-64765, you should upgrade to Astro version 5.15.8 or later.

3

What types of attacks can exploit CVE-2025-64765?

CVE-2025-64765 can be exploited through crafted requests that manipulate routing paths, potentially bypassing validation checks.

4

Which versions of Astro are affected by CVE-2025-64765?

CVE-2025-64765 affects all versions of Astro prior to version 5.15.8.

5

Is there a workaround for CVE-2025-64765 if I cannot upgrade?

There are no recommended workarounds for CVE-2025-64765; upgrading to a patched version is the best approach.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203