Skip to content

Commit fd2abee

Browse files
chore(deps): update dependency astro to v5.15.9 [security] (#1158)
This PR contains the following updates: | Package | Change | Age | Confidence | |---|---|---|---| | [astro](https://astro.build) ([source](https://redirect.github.com/withastro/astro/tree/HEAD/packages/astro)) | [`5.15.6` -> `5.15.9`](https://renovatebot.com/diffs/npm/astro/5.15.6/5.15.9) | [![age](https://developer.mend.io/api/mc/badges/age/npm/astro/5.15.9?slim=true)](https://docs.renovatebot.com/merge-confidence/) | [![confidence](https://developer.mend.io/api/mc/badges/confidence/npm/astro/5.15.6/5.15.9?slim=true)](https://docs.renovatebot.com/merge-confidence/) | ### GitHub Vulnerability Alerts #### [CVE-2025-64764](https://redirect.github.com/withastro/astro/security/advisories/GHSA-wrwg-2hg8-v723) ## Summary After some research it appears that it is possible to obtain a reflected XSS when the server islands feature is used in the targeted application, **regardless of what was intended by the component template(s)**. ## Details Server islands run in their own isolated context outside of the page request and use the following pattern path to hydrate the page: `/_server-islands/[name]`. These paths can be called via GET or POST and use three parameters: - `e`: component to export - `p`: the transmitted properties, encrypted - `s`: for the slots Slots are placeholders for external HTML content, and therefore allow, by default, the injection of code if the component template supports it, nothing exceptional in principle, just a feature. This is where it becomes problematic: it is possible, independently of the component template used, even if it is completely empty, to inject a slot containing an XSS payload, whose parent is a tag whose name is is the absolute path of the island file. Enabling reflected XSS on any application, regardless of the component templates used, provided that the server islands is used at least once. **How ?** By default, when a call is made to the endpoint `/_server-islands/[name]`, the value of the parameter `e` is `default`, pointing to a function exported by the component's module. Upon further investigation, we find that two other values ​​are possible for the component export (param `e`) in a typical configuration: `url` and `file`. `file` returns a string value corresponding to the absolute path of the island file. Since the value is of type `string`, it fulfills the following condition and leads to [this code block](https://redirect.github.com/withastro/astro/blob/190106149908ef6826899459146ef9f0ead602ab/packages/astro/src/runtime/server/render/component.ts#L279): <img width="804" height="571" alt="image" src="https://github.com/user-attachments/assets/25ea6c16-fc27-477a-a1ad-e5edf0819b31" /> An entire template is created, completely independently, and then returned: - the absolute path name is sanitized and then injected as the tag name - `childSlots`, the value provided to the `s` parameter, is injected as a child All of this is done using `markHTMLString`. This allows the injection of any XSS payload, **even if the component template intended by the application is initially empty or does not provide for the use of slots.** ## Proof of concept For our Proof of Concept (PoC), we will use a minimal repository: - Latest Astro version at the time (5.15.6) - Use of Island servers, with a completely empty component, to demonstrate what we explained previously [Download the PoC repository](https://redirect.github.com/zhero-web-sec/astro-app-2) Access the following URL and note the opening of the popup, demonstrating the reflected XSS: http://localhost:4321/_server-islands/ServerTime?e=file&p=&s={%22zhero%22:%22%3Cimg%20src=x%20onerror=alert(0)%3E%22} <img width="1781" height="529" alt="image" src="https://github.com/user-attachments/assets/92f8134a-d1c7-4d3f-818e-214842c239c8" /> The value of the parameter `s` must be in JSON format and the payload must be injected at the value level, not the key level : <img width="3273" height="1840" alt="for_respected_patron" src="https://github.com/user-attachments/assets/8ac0079a-3dee-49e8-b639-322f77c84b83" /> Despite the initial template being empty, it is created because the value of the URL parameter `e` is set to `file`, as explained earlier. The parent tag is the name of the component's internal route, and its child is the value of the key "zhero" (*the name doesn't matter*) of the URL parameter `s`. ## Credits - Allam Rachid ([zhero;](https://zhero-web-sec.github.io/research-and-things/)) - Allam Yasser (inzo) #### [CVE-2025-64765](https://redirect.github.com/withastro/astro/security/advisories/GHSA-ggxq-hp9w-j794) 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); ``` Thankyou, let me know if any more info is needed happy to help :) #### [CVE-2025-65019](https://redirect.github.com/withastro/astro/security/advisories/GHSA-fvmw-cj7j-j39q) ## Summary When using Astro's Cloudflare adapter (@&#8203;astrojs/cloudflare) with `output: 'server'`, the image optimization endpoint (`/_image`) contains a critical vulnerability in the `isRemoteAllowed()` function that unconditionally allows `data:` protocol URLs. This enables Cross-Site Scripting (XSS) attacks through malicious SVG payloads, bypassing domain restrictions and Content Security Policy protections. ## Details On-demand rendered sites built with Astro include an `/_image` endpoint for image optimization. While this endpoint is designed to restrict processing to local images and authorized remote domains (configured via `image.domains` or `image.remotePatterns`), a critical vulnerability exists in the underlying validation logic. The `isRemoteAllowed()` function in [packages/internal-helpers/src/remote.ts](https://redirect.github.com/withastro/astro/blob/b8ca69b97149becefaf89bf21853de9c905cdbb7/packages/internal-helpers/src/remote.ts) (lines 128-131) unconditionally allows ALL `data:` protocol URLs without any validation or sanitization. When combined with SVG images containing JavaScript, this creates a vector for XSS attacks. **Vulnerable Code:** ```JavaScript /packages/ packages/internal-helpers/src/remote.ts lines 128-131 if (url.protocol === 'data:') { return true; // ← Unconditionally allows ALL data: URLs! } ``` The vulnerability manifests differently depending on the image endpoint implementation: - **Safe implementation**: Server processes SVG and converts to raster format (PNG/JPEG), removing JavaScript - **Vulnerable implementation**: Server redirects browser to raw SVG data URL, allowing JavaScript execution ### PoC 1. Create a new minimal Astro project (astro@latest) 2. Configure it to use the Cloudflare adapter (@&#8203;astrojs/[email protected]) 3. Deploy to Cloudflare Pages or Workers. 4. Write page to load SVG Image like : [SVG XSS Payload](https://gist.github.com/rudSarkar/76f1ce7a65c356a5cd71d058ab76a344) 5. Open directly the SVG file to show an alert (in read scenarios, the apps that use the framework will use CDN for example, to load SVG, depending that the framework is secure) ### Impact 1. **Stored XSS**: Malicious URLs can be crafted to execute JavaScript in victim's browser 2. **Session Hijacking**: JavaScript can access cookies and session tokens 3. **Account Takeover**: Combined with CSRF, can perform unauthorized actions 4. **Data Exfiltration**: Sensitive information can be stolen and sent to attacker-controlled servers ### References - **Vulnerable Function**: [packages/internal-helpers/src/remote.ts](https://redirect.github.com/withastro/astro/blob/b8ca69b97149becefaf89bf21853de9c905cdbb7/packages/internal-helpers/src/remote.ts) lines 128-131 - **Similar Vulnerability**:: https://dailycve.com/wordpress-stored-xss-via-svg-upload-cve-2025-2575-medium/ --- ### Release Notes <details> <summary>withastro/astro (astro)</summary> ### [`v5.15.9`](https://redirect.github.com/withastro/astro/blob/HEAD/packages/astro/CHANGELOG.md#5159) [Compare Source](https://redirect.github.com/withastro/astro/compare/[email protected]@5.15.9) ##### Patch Changes - [#&#8203;14786](https://redirect.github.com/withastro/astro/pull/14786) [`758a891`](https://redirect.github.com/withastro/astro/commit/758a891112839a108479fd0489a1785640b31ecf) Thanks [@&#8203;mef](https://redirect.github.com/mef)! - Add handling of invalid encrypted props and slots in server islands. - [#&#8203;14783](https://redirect.github.com/withastro/astro/pull/14783) [`504958f`](https://redirect.github.com/withastro/astro/commit/504958fe7fccd7bffc177a1f4b1bf4e22989470e) Thanks [@&#8203;florian-lefebvre](https://redirect.github.com/florian-lefebvre)! - Improves the experimental Fonts API build log to show the number of downloaded files. This can help spotting excessive downloading because of misconfiguration - [#&#8203;14791](https://redirect.github.com/withastro/astro/pull/14791) [`9e9c528`](https://redirect.github.com/withastro/astro/commit/9e9c528191b6f5e06db9daf6ad26b8f68016e533) Thanks [@&#8203;Princesseuh](https://redirect.github.com/Princesseuh)! - Changes the remote protocol checks for images to require explicit authorization in order to use data URIs. In order to allow data URIs for remote images, you will need to update your `astro.config.mjs` file to include the following configuration: ```js // astro.config.mjs import { defineConfig } from 'astro/config'; export default defineConfig({ images: { remotePatterns: [ { protocol: 'data', }, ], }, }); ``` - [#&#8203;14787](https://redirect.github.com/withastro/astro/pull/14787) [`0f75f6b`](https://redirect.github.com/withastro/astro/commit/0f75f6bc637d547e07324e956db21d9f245a3e8e) Thanks [@&#8203;matthewp](https://redirect.github.com/matthewp)! - Fixes wildcard hostname pattern matching to correctly reject hostnames without dots Previously, hostnames like `localhost` or other single-part names would incorrectly match patterns like `*.example.com`. The wildcard matching logic has been corrected to ensure that only valid subdomains matching the pattern are accepted. - [#&#8203;14776](https://redirect.github.com/withastro/astro/pull/14776) [`3537876`](https://redirect.github.com/withastro/astro/commit/3537876fde3bdb2a0ded99cc9b00d53f66160a7f) Thanks [@&#8203;ktym4a](https://redirect.github.com/ktym4a)! - Fixes the behavior of `passthroughImageService` so it does not generate webp. - Updated dependencies \[[`9e9c528`](https://redirect.github.com/withastro/astro/commit/9e9c528191b6f5e06db9daf6ad26b8f68016e533), [`0f75f6b`](https://redirect.github.com/withastro/astro/commit/0f75f6bc637d547e07324e956db21d9f245a3e8e)]: - [@&#8203;astrojs/internal-helpers](https://redirect.github.com/astrojs/internal-helpers)@&#8203;0.7.5 - [@&#8203;astrojs/markdown-remark](https://redirect.github.com/astrojs/markdown-remark)@&#8203;6.3.9 ### [`v5.15.8`](https://redirect.github.com/withastro/astro/blob/HEAD/packages/astro/CHANGELOG.md#5158) [Compare Source](https://redirect.github.com/withastro/astro/compare/[email protected]@5.15.8) ##### Patch Changes - [#&#8203;14772](https://redirect.github.com/withastro/astro/pull/14772) [`00c579a`](https://redirect.github.com/withastro/astro/commit/00c579a23322d92459e4ccad0ec365c4d1980a5d) Thanks [@&#8203;matthewp](https://redirect.github.com/matthewp)! - Improves the security of Server Islands slots by encrypting them before transmission to the browser, matching the security model used for props. This improves the integrity of slot content and prevents injection attacks, even when component templates don't explicitly support slots. Slots continue to work as expected for normal usage—this change has no breaking changes for legitimate requests. - [#&#8203;14771](https://redirect.github.com/withastro/astro/pull/14771) [`6f80081`](https://redirect.github.com/withastro/astro/commit/6f800813516b07bbe12c666a92937525fddb58ce) Thanks [@&#8203;matthewp](https://redirect.github.com/matthewp)! - Fix middleware pathname matching by normalizing URL-encoded paths Middleware now receives normalized pathname values, ensuring that encoded paths like `/%61dmin` are properly decoded to `/admin` before middleware checks. This prevents potential security issues where middleware checks might be bypassed through URL encoding. ### [`v5.15.7`](https://redirect.github.com/withastro/astro/blob/HEAD/packages/astro/CHANGELOG.md#5157) [Compare Source](https://redirect.github.com/withastro/astro/compare/[email protected]@5.15.7) ##### Patch Changes - [#&#8203;14765](https://redirect.github.com/withastro/astro/pull/14765) [`03fb47c`](https://redirect.github.com/withastro/astro/commit/03fb47c0106fda823e4dc89ed98d282ecb5258a0) Thanks [@&#8203;florian-lefebvre](https://redirect.github.com/florian-lefebvre)! - Fixes a case where `process.env` wouldn't be properly populated during the build - [#&#8203;14690](https://redirect.github.com/withastro/astro/pull/14690) [`ae7197d`](https://redirect.github.com/withastro/astro/commit/ae7197d35676b3745dc9ca71aecbcf3bbbfffb30) Thanks [@&#8203;fredriknorlin](https://redirect.github.com/fredriknorlin)! - Fixes a bug where Astro's i18n fallback system with `fallbackType: 'rewrite'` would not generate fallback files for pages whose filename started with a locale key. </details> --- ### Configuration 📅 **Schedule**: Branch creation - "" (UTC), Automerge - At any time (no schedule defined). 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/yorukot/superfile). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0MS4xNzMuMSIsInVwZGF0ZWRJblZlciI6IjQyLjE2LjEiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
1 parent e6aa7da commit fd2abee

File tree

1 file changed

+133
-133
lines changed

1 file changed

+133
-133
lines changed

0 commit comments

Comments
 (0)