{"id":"GHSA-prjg-x2qj-wj3g","kind":"vulnerability","aliases":["GHSA-prjg-x2qj-wj3g"],"related":[],"title":"SSRF via redirects in server-side self-fetch fallbacks","description":"### Impact\r\n\r\nIn certain circumstances, SvelteKit makes server-side fallback requests to URLs derived from the incoming request origin. These self-fetches occur when retrieving prerendered data for experimental `prerender` remote functions, serving rerouted prerendered content, fetching static or prerendered resources without an internal read implementation, and handling same-origin subrequests that cannot be resolved from the server manifest (including during error-page rendering).\r\n\r\nIf an attacker can influence the request origin and trigger one of these fallback paths, SvelteKit can make a request to an attacker-controlled server. These requests previously followed HTTP redirects automatically, allowing that server to redirect the request to an internal service and cause server-side request forgery (SSRF).\r\n\r\nExposure depends on the adapter and deployment configuration. For example, this can occur with `adapter-node` when the request origin is derived from unvalidated `Host` or forwarded host/protocol headers.\r\n\r\n### Patches\r\n\r\nFixed in version 3.0.0.\r\n\r\nThe fix disables automatic redirect following for these framework self-fetch fallbacks. It prevents an attacker-controlled first response from causing further server-side requests through redirects; it does not validate or restrict the origin of the initial request.\r\n\r\n### Workarounds\r\n\r\nConfigure a trusted fixed request origin where supported. For `adapter-node`, set the `paths.origin` configuration to the application’s trusted origin. Alternatively, use a trusted reverse proxy that validates the allowed request hosts and supplies trusted host/protocol metadata. Forwarded headers used to construct the request origin must not be accepted directly from untrusted clients.","summary":"SvelteKit's server makes internal self-fetch requests to URLs built from the incoming request origin, and it followed HTTP redirects on those requests. An attacker who controls the origin and a server they host can redirect the server to internal services, reaching targets the attacker could not reach directly.","severity":"medium","cvss":5.3,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"@sveltejs/kit","fixed":[">= 2.70.4"],"affected":"<= 2.70.3","ecosystem":"npm"}],"ecosystems":["npm"],"tags":["adapter-node","node","package","self-hosted","svelte","sveltekit"],"not_affected_if":["default-config","managed-hosting","static-export"],"how_to_check":"- Check the installed version: `npm ls @sveltejs/kit`\n- Look for `adapter-node` and whether the origin comes from the `Host` or forwarded headers without validation\n- Check whether `paths.origin` is set in `svelte.config.js`","fix":"- `@sveltejs/kit`: move to `3.0.0` or later (affected up to `2.70.3`, fixed from `2.70.4` per product data; advisory says fixed in `3.0.0`)\n- Workaround: set `paths.origin` to the trusted origin for `adapter-node`, or validate hosts at a trusted reverse proxy","status":"open","published_at":"2026-10-05T19:34:37+00:00","first_seen_at":"2026-11-09T22:53:16+00:00","triaged_at":"2026-11-09T23:01:10+00:00","updated_at":"2026-11-09T23:01:10+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-09T23:01:10Z","model":"claude-haiku-5-5","output":{"fix":"- `@sveltejs/kit`: move to `3.0.0` or later (affected up to `2.70.3`, fixed from `2.70.4` per product data; advisory says fixed in `3.0.0`)\n- Workaround: set `paths.origin` to the trusted origin for `adapter-node`, or validate hosts at a trusted reverse proxy","reach":"internet","title":"SvelteKit: server self-fetch follows redirects, enabling server-side request forgery","impact":"medium","summary":"SvelteKit's server makes internal self-fetch requests to URLs built from the incoming request origin, and it followed HTTP redirects on those requests. An attacker who controls the origin and a server they host can redirect the server to internal services, reaching targets the attacker could not reach directly.","audience":"developers","category":"package","nicknames":[],"who_cares":["sveltekit","svelte","node","self-hosted","adapter-node"],"confidence":0.8,"fix_status":"available","needs_auth":"no","worst_case":"Server sends requests to internal services, leaking internal data","analyst_note":"","how_to_check":"- Check the installed version: `npm ls @sveltejs/kit`\n- Look for `adapter-node` and whether the origin comes from the `Host` or forwarded headers without validation\n- Check whether `paths.origin` is set in `svelte.config.js`","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["static-export","managed-hosting","default-config"],"who_is_affected":"Applications built on SvelteKit that run server-side code, most often with adapter-node, where the request origin is taken from unvalidated Host or forwarded headers. Exposure depends on the adapter and deployment; static or fully prerendered sites with no server fallbacks are unlikely to be affected.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"medium"},"cost_usd":0.000839,"input_tokens":5050,"output_tokens":669,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'3.0.0':237C 'accept':331C 'adapt':24B,207C,218C,291C 'adapter-nod':23B,217C,290C 'allow':184C,312C 'altern':303C 'applic':299C 'attack':59B,79B,153C,174C,255C 'attacker-control':173C,254C 'automat':183C,241C 'built':44B 'cannot':138C 'caus':196C,260C 'certain':86C 'circumst':87C 'client':335C 'configur':210C,281C,296C 'construct':324C 'content':120C 'control':61B,175C,256C 'could':80B 'data':111C 'depend':204C 'deploy':209C 'deriv':97C,225C 'direct':83B,332C 'disabl':240C 'error':148C 'error-pag':147C 'exampl':212C 'experiment':113C 'exposur':203C 'fallback':11A,93C,164C,250C 'fetch':10A,40B,106C,121C,249C 'first':257C 'fix':234C,239C,284C 'follow':52B,180C,243C 'forgeri':201C 'forward':230C,320C 'framework':246C 'function':116C 'ghsa':13A,18A 'ghsa-prjg-x2qj-wj3g':12A,17A 'handl':132C 'header':232C,321C 'host':30B,68B,228C,314C 'host/protocol':231C,318C 'http':53B,181C 'impact':84C 'implement':130C 'includ':145C 'incom':47B,100C 'influenc':155C 'initi':278C 'intern':37B,74B,128C,193C 'make':36B,89C,168C 'manifest':144C 'metadata':319C 'must':328C 'node':25B,26B,219C,292C 'occur':107C,215C 'one':161C 'origin':49B,63B,102C,135C,158C,223C,275C,286C,302C,327C 'packag':27B 'page':149C 'patch':233C 'path':165C 'paths.origin':295C 'prerend':110C,114C,119C,124C 'prevent':252C 'previous':179C 'prjg':14A,19A 'proxi':308C 'reach':76B,82B 'read':129C 'redirect':3A,54B,70B,182C,188C,242C,267C 'remot':115C 'render':150C 'request':41B,48B,57B,94C,101C,157C,170C,178C,190C,200C,222C,265C,279C,285C,313C,326C 'rerout':118C 'resolv':140C 'resourc':125C 'respons':258C 'restrict':273C 'retriev':109C 'revers':307C 'same-origin':133C 'self':9A,29B,39B,105C,248C 'self-fetch':8A,38B,104C,247C 'self-host':28B 'serv':117C 'server':6A,35B,66B,72B,91C,143C,176C,186C,198C,263C 'server-sid':5A,90C,197C,262C 'servic':75B,194C 'set':293C 'side':7A,92C,199C,264C 'ssrf':1A,202C 'static':122C 'subrequest':136C 'suppli':316C 'support':288C 'svelt':31B 'sveltejs/kit':22A 'sveltekit':32B,33B,88C,166C 'target':77B 'trigger':160C 'trust':283C,301C,306C,317C 'untrust':334C 'unvalid':227C 'url':43B,96C 'use':304C,322C 'valid':271C,310C 'version':236C 'via':2A 'without':126C 'wj3g':16A,21A 'workaround':280C 'x2qj':15A,20A","nicknames":[],"mitigations":[],"who_affected":"Applications built on SvelteKit that run server-side code, most often with adapter-node, where the request origin is taken from unvalidated Host or forwarded headers. Exposure depends on the adapter and deployment; static or fully prerendered sites with no server fallbacks are unlikely to be affected.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["kit"],"ptokens":["kit","sveltejs"],"labels":["adapternode","medium","node","npm","package","selfhosted","svelte","sveltekit"],"campaign_type":null,"search_a":"'fallback':11A 'fetch':10A 'ghsa':13A,18A 'ghsa-prjg-x2qj-wj3g':12A,17A 'prjg':14A,19A 'redirect':3A 'self':9A 'self-fetch':8A 'server':6A 'server-sid':5A 'side':7A 'ssrf':1A 'sveltejs/kit':22A 'via':2A 'wj3g':16A,21A 'x2qj':15A,20A","search_b":"'adapt':24B 'adapter-nod':23B 'attack':59B,79B 'built':44B 'control':61B 'could':80B 'direct':83B 'fetch':40B 'follow':52B 'host':30B,68B 'http':53B 'incom':47B 'intern':37B,74B 'make':36B 'node':25B,26B 'origin':49B,63B 'packag':27B 'reach':76B,82B 'redirect':54B,70B 'request':41B,48B,57B 'self':29B,39B 'self-fetch':38B 'self-host':28B 'server':35B,66B,72B 'servic':75B 'svelt':31B 'sveltekit':32B,33B 'target':77B 'url':43B","search_c":"'3.0.0':237C 'accept':331C 'adapt':207C,218C,291C 'adapter-nod':217C,290C 'allow':184C,312C 'altern':303C 'applic':299C 'attack':153C,174C,255C 'attacker-control':173C,254C 'automat':183C,241C 'cannot':138C 'caus':196C,260C 'certain':86C 'circumst':87C 'client':335C 'configur':210C,281C,296C 'construct':324C 'content':120C 'control':175C,256C 'data':111C 'depend':204C 'deploy':209C 'deriv':97C,225C 'direct':332C 'disabl':240C 'error':148C 'error-pag':147C 'exampl':212C 'experiment':113C 'exposur':203C 'fallback':93C,164C,250C 'fetch':106C,121C,249C 'first':257C 'fix':234C,239C,284C 'follow':180C,243C 'forgeri':201C 'forward':230C,320C 'framework':246C 'function':116C 'handl':132C 'header':232C,321C 'host':228C,314C 'host/protocol':231C,318C 'http':181C 'impact':84C 'implement':130C 'includ':145C 'incom':100C 'influenc':155C 'initi':278C 'intern':128C,193C 'make':89C,168C 'manifest':144C 'metadata':319C 'must':328C 'node':219C,292C 'occur':107C,215C 'one':161C 'origin':102C,135C,158C,223C,275C,286C,302C,327C 'page':149C 'patch':233C 'path':165C 'paths.origin':295C 'prerend':110C,114C,119C,124C 'prevent':252C 'previous':179C 'proxi':308C 'read':129C 'redirect':182C,188C,242C,267C 'remot':115C 'render':150C 'request':94C,101C,157C,170C,178C,190C,200C,222C,265C,279C,285C,313C,326C 'rerout':118C 'resolv':140C 'resourc':125C 'respons':258C 'restrict':273C 'retriev':109C 'revers':307C 'same-origin':133C 'self':105C,248C 'self-fetch':104C,247C 'serv':117C 'server':91C,143C,176C,186C,198C,263C 'server-sid':90C,197C,262C 'servic':194C 'set':293C 'side':92C,199C,264C 'ssrf':202C 'static':122C 'subrequest':136C 'suppli':316C 'support':288C 'sveltekit':88C,166C 'trigger':160C 'trust':283C,301C,306C,317C 'untrust':334C 'unvalid':227C 'url':96C 'use':304C,322C 'valid':271C,310C 'version':236C 'without':126C 'workaround':280C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-10-05T19:34:37+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-prjg-x2qj-wj3g","url":"https://github.com/sveltejs/kit/security/advisories/GHSA-prjg-x2qj-wj3g","severity":"medium","published_at":"2026-10-05T19:34:37+00:00","modified_at":"2026-10-05T19:34:37+00:00","first_seen_at":"2026-11-09T22:53:16+00:00","fetched_at":"2026-11-09T22:53:16+00:00","note":null}],"documents":[{"id":45720,"url":"https://github.com/sveltejs/kit/security/advisories/GHSA-prjg-x2qj-wj3g","title":"Vendor advisory: github.com","kind":"vendor","source":"nvd","publisher":"vendor","text":null,"published_at":"2026-10-05T19:34:37+00:00","relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}