VYPR
High severityOSV Advisory· Published Jan 15, 2026· Updated Jan 15, 2026

SvelteKit Denial of service and possible SSRF when using prerendering

CVE-2025-67647

Description

SvelteKit is a framework for rapidly developing robust, performant web applications using Svelte. Prior to 2.49.5, SvelteKit is vulnerable to a server side request forgery (SSRF) and denial of service (DoS) under certain conditions. From 2.44.0 through 2.49.4, the vulnerability results in a DoS when your app has at least one prerendered route (export const prerender = true). From 2.19.0 through 2.49.4, the vulnerability results in a DoS when your app has at least one prerendered route and you are using adapter-node without a configured ORIGIN environment variable, and you are not using a reverse proxy that implements Host header validation. This vulnerability is fixed in 2.49.5.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
@sveltejs/kitnpm
>= 2.19.0, < 2.49.52.49.5
@sveltejs/adapter-nodenpm
>= 5.4.1, < 5.5.15.5.1

Affected products

1
  • Range: @sveltejs/adapter-auto@5.0.0, @sveltejs/adapter-auto@6.0.0, @sveltejs/adapter-auto@6.0.1, …

Patches

1
d9ae9b00b14f

Merge commit from fork

https://github.com/sveltejs/kitTee MingJan 15, 2026via ghsa
4 files changed · +73 18
  • .changeset/six-geese-ring.md+5 0 added
    @@ -0,0 +1,5 @@
    +---
    +'@sveltejs/adapter-node': patch
    +---
    +
    +fix: add validations for protocol, host, and port header values
    
  • .changeset/slow-pears-follow.md+5 0 added
    @@ -0,0 +1,5 @@
    +---
    +'@sveltejs/kit': patch
    +---
    +
    +fix: ensure url decoded pathnames are not mistaken as rerouted requests
    
  • packages/adapter-node/src/handler.js+43 4 modified
    @@ -179,14 +179,53 @@ function sequence(handlers) {
     	};
     }
     
    +/**
    + * @param {string} name
    + * @param {string | string[] | undefined} value
    + * @returns {string | undefined}
    + */
    +function normalise_header(name, value) {
    +	if (!name) return undefined;
    +	if (Array.isArray(value)) {
    +		if (value.length === 0) return undefined;
    +		if (value.length === 1) return value[0];
    +		throw new Error(
    +			`Multiple values provided for ${name} header where only one expected: ${value}`
    +		);
    +	}
    +	return value;
    +}
    +
     /**
      * @param {import('http').IncomingHttpHeaders} headers
    - * @returns
    + * @returns {string}
      */
     function get_origin(headers) {
    -	const protocol = (protocol_header && headers[protocol_header]) || 'https';
    -	const host = (host_header && headers[host_header]) || headers['host'];
    -	const port = port_header && headers[port_header];
    +	const protocol = decodeURIComponent(normalise_header(protocol_header, headers[protocol_header]) || 'https');
    +
    +	// this helps us avoid host injections through the protocol header
    +	if (protocol.includes(':')) {
    +		throw new Error(
    +			`The ${protocol_header} header specified ${protocol} which is an invalid because it includes \`:\`. It should only contain the protocol scheme (e.g. \`https\`)`
    +		);
    +	}
    +
    +	const host =
    +		normalise_header(host_header, headers[host_header]) ||
    +		normalise_header('host', headers['host']);
    +	if (!host) {
    +		const header_names = host_header ? `${host_header} or host headers` : 'host header';
    +		throw new Error(
    +			`Could not determine host. The request must have a value provided by the ${header_names}`
    +		);
    +	}
    +
    +	const port = normalise_header(port_header, headers[port_header]);
    +	if (port && isNaN(+port)) {
    +		throw new Error(
    +			`The ${port_header} header specified ${port} which is an invalid port because it is not a number. The value should only contain the port number (e.g. 443)`
    +		);
    +	}
     
     	return port ? `${protocol}://${host}:${port}` : `${protocol}://${host}`;
     }
    
  • packages/kit/src/runtime/server/respond.js+20 14 modified
    @@ -247,8 +247,10 @@ export async function internal_respond(request, options, manifest, state) {
     		return text('Malformed URI', { status: 400 });
     	}
     
    +	// try to serve the rerouted prerendered resource if it exists
     	if (
    -		resolved_path !== url.pathname &&
    +		// the resolved path has been decoded so it should be compared to the decoded url pathname
    +		resolved_path !== decode_pathname(url.pathname) &&
     		!state.prerendering?.fallback &&
     		has_prerendered_path(manifest, resolved_path)
     	) {
    @@ -259,20 +261,24 @@ export async function internal_respond(request, options, manifest, state) {
     				? add_resolution_suffix(resolved_path)
     				: resolved_path;
     
    -		// `fetch` automatically decodes the body, so we need to delete the related headers to not break the response
    -		// Also see https://github.com/sveltejs/kit/issues/12197 for more info (we should fix this more generally at some point)
    -		const response = await fetch(url, request);
    -		const headers = new Headers(response.headers);
    -		if (headers.has('content-encoding')) {
    -			headers.delete('content-encoding');
    -			headers.delete('content-length');
    -		}
    +		try {
    +			// `fetch` automatically decodes the body, so we need to delete the related headers to not break the response
    +			// Also see https://github.com/sveltejs/kit/issues/12197 for more info (we should fix this more generally at some point)
    +			const response = await fetch(url, request);
    +			const headers = new Headers(response.headers);
    +			if (headers.has('content-encoding')) {
    +				headers.delete('content-encoding');
    +				headers.delete('content-length');
    +			}
     
    -		return new Response(response.body, {
    -			headers,
    -			status: response.status,
    -			statusText: response.statusText
    -		});
    +			return new Response(response.body, {
    +				headers,
    +				status: response.status,
    +				statusText: response.statusText
    +			});
    +		} catch (error) {
    +			return await handle_fatal_error(event, event_state, options, error);
    +		}
     	}
     
     	/** @type {import('types').SSRRoute | null} */
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

6

News mentions

0

No linked articles in our index yet.