{"id":"CVE-2025-32388","kind":"vulnerability","aliases":["CVE-2025-32388","GHSA-6q87-84jw-cjhp"],"related":[],"title":"@sveltejs/kit vulnerable to Cross-site Scripting via tracked search_params","description":"### Summary\n\nUnsanitized search param names cause XSS vulnerability. You are affected if you iterate over all entries of `event.url.searchParams` inside a server `load` function. Attackers can exploit it by crafting a malicious URL and getting a user to click a link with said URL.\n\n### Details\n\nSvelteKit tracks which parameters in `event.url.searchParams` are read inside server `load` functions. If the application iterates over the these parameters, the `uses.search_params` array included in the boot script (embedded in the server-rendered HTML) will have any search param name included in unsanitized form.\n\n`packages/kit/src/runtime/server/utils.js:150` has the `stringify_uses(node)` function which prints these out.\n\n### Reproduction\n\nIn a `+page.server.js` or `+layout.server.js`:\n\n```js\n/** @type {import('@sveltejs/kit').Load} */\nexport function load(event) {\n  const values = {};\n\n  for (const key of event.url.searchParams.keys()) {\n    values[key] = event.url.searchParams.get(key);\n  }\n}\n```\n\nIf a user visits the page in question via a link containing `?</script/><script>window.pwned%3D1</script/>`, the `</script>` will be included verbatim in the payload, causing the embedded script to be executed.\n\nIt is not necessary to return the parameter value from `load` or render it in the page, only to read it (which causes it to be tracked as a dependency) while `load` is running.\n\n### Impact\n\nAny application that iterates over all values in `event.url.searchParams` in a `load` function in `+page.server.js` or `+layout.server.js` (directly or indirectly) is vulnerable to XSS.","summary":"SvelteKit embeds unsanitized search parameter names in the page's boot script when a server load function iterates over all of event.url.searchParams. An attacker who gets a user to open a crafted link can run arbitrary JavaScript in that user's browser on the site.","severity":"medium","cvss":5.400000095367432,"epss":0.0030400000978261232,"exploited":false,"exploited_at":null,"products":[{"name":"@sveltejs/kit","fixed":["2.20.6"],"affected":">= 2.0.0, < 2.20.6","ecosystem":"npm"}],"ecosystems":["npm"],"tags":["cwe-79","next.js","package","sveltekit"],"not_affected_if":["no-server-load-iterating-searchparams","pinned-below-2.0.0","static-export"],"how_to_check":"Search server load functions in +page.server.js and +layout.server.js for iteration over event.url.searchParams (keys(), entries(), forEach, for...of).\nCheck the installed version: npm ls @sveltejs/kit","fix":"Upgrade @sveltejs/kit to 2.20.6 or later.\nUntil upgraded, avoid iterating over all searchParams entries in server load functions.","status":"open","published_at":"2025-04-14T19:10:42+00:00","first_seen_at":"2026-10-23T19:11:32+00:00","triaged_at":"2026-10-23T21:48:50+00:00","updated_at":"2026-10-23T21:48:50+00:00","category":"package","confidence":0.85,"triage":{"at":"2026-10-23T21:48:50Z","model":"claude-haiku-5-5","output":{"fix":"Upgrade @sveltejs/kit to 2.20.6 or later.\nUntil upgraded, avoid iterating over all searchParams entries in server load functions.","reach":"internet","impact":"high","summary":"SvelteKit embeds unsanitized search parameter names in the page's boot script when a server load function iterates over all of event.url.searchParams. An attacker who gets a user to open a crafted link can run arbitrary JavaScript in that user's browser on the site.","category":"package","who_cares":["sveltekit","next.js"],"confidence":0.85,"needs_auth":"no","worst_case":"Attacker runs arbitrary JavaScript in victims' browsers via crafted link","analyst_note":"","how_to_check":"Search server load functions in +page.server.js and +layout.server.js for iteration over event.url.searchParams (keys(), entries(), forEach, for...of).\nCheck the installed version: npm ls @sveltejs/kit","needs_analyst":false,"not_affected_if":["no-server-load-iterating-searchparams","static-export","pinned-below-2.0.0"],"user_interaction":"yes","needs_special_setup":"yes","severity_if_unknown":"unknown"},"cost_usd":0.00054,"input_tokens":3300,"output_tokens":419,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-2025':13A,21A '-32388':14A,22A '-79':25B '150':166C '6q87':17A '84jw':18A 'affect':84C 'applic':133C,265C 'arbitrari':64B 'array':142C 'attack':52B,98C 'boot':39B,146C 'browser':70B 'caus':79C,222C,251C 'cjhp':19A 'click':112C 'const':192C,195C 'contain':214C 'craft':60B,103C 'cross':5A 'cross-sit':4A 'cve':12A,20A 'cwe':24B 'depend':258C 'detail':118C 'direct':281C 'emb':30B 'embed':148C,224C 'entri':90C 'event':191C 'event.url.searchparams':50B,92C,124C,272C 'event.url.searchparams.get':201C 'event.url.searchparams.keys':198C 'execut':228C 'exploit':100C 'export':188C 'form':164C 'function':45B,97C,130C,172C,189C,276C 'get':54B,108C 'ghsa':16A 'ghsa-6q87-84jw-cjhp':15A 'html':154C 'impact':263C 'import':185C 'includ':143C,161C,217C 'indirect':283C 'insid':93C,127C 'iter':46B,87C,134C,267C 'javascript':65B 'js':183C 'key':196C,200C,202C 'layout.server.js':182C,280C 'link':61B,114C,213C 'load':44B,96C,129C,187C,190C,239C,260C,275C 'malici':105C 'name':34B,78C,160C 'necessari':232C 'next.js':26B 'node':171C 'open':58B 'packag':27B 'packages/kit/src/runtime/server/utils.js':165C 'page':37B,208C,245C 'page.server.js':180C,278C 'param':11A,77C,141C,159C 'paramet':33B,122C,138C,236C 'payload':221C 'print':174C 'question':210C 'read':126C,248C 'render':153C,241C 'reproduct':177C 'return':234C 'run':63B,262C 'said':116C 'script':7A,40B,147C,225C 'search':10A,32B,76C,158C 'server':43B,95C,128C,152C 'server-rend':151C 'site':6A,73B 'stringifi':169C 'summari':74C 'sveltejs/kit':1A,23A,186C 'sveltekit':28B,29B,119C 'track':9A,120C,255C 'type':184C 'unsanit':31B,75C,163C 'url':106C,117C 'use':170C 'user':56B,68B,110C,205C 'uses.search':140C 'valu':193C,199C,237C,270C 'verbatim':218C 'via':8A,211C 'visit':206C 'vulner':2A,81C,285C 'xss':80C,287C","nicknames":[],"mitigations":[],"who_affected":null,"tier":null,"verified":{},"analyst_revisit_at":null,"first_public_at":"2025-04-14T19:10:42+00:00","kev":null,"cvss_vector":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N","cvss_by":"GitHub","poc_count":0,"sources":[{"source":"ghsa","external_id":"GHSA-6q87-84jw-cjhp","url":"https://github.com/advisories/GHSA-6q87-84jw-cjhp","severity":"medium","published_at":"2025-04-14T19:10:42+00:00","modified_at":"2026-10-18T15:04:06+00:00","first_seen_at":"2026-10-23T19:11:32+00:00","fetched_at":"2026-10-23T19:11:32+00:00","note":null},{"source":"nvd","external_id":"CVE-2025-32388","url":"https://nvd.nist.gov/vuln/detail/CVE-2025-32388","severity":null,"published_at":"2025-04-15T23:15:42+00:00","modified_at":"2026-06-17T09:11:55+00:00","first_seen_at":"2026-10-23T23:44:52+00:00","fetched_at":"2026-10-23T23:44:52+00:00","note":null}],"documents":[],"notice":"Free to read at a human pace. An API with keys and an MCP server are in preparation; early access: hello@infrastack.ai"}