{"id":"CVE-2026-119350","kind":"vulnerability","aliases":["CVE-2026-119350","GHSA-vvgp-ww4w-46vf"],"related":[],"title":"Cache poisoning of shared fallback shells in Cache Components via request-supplied placeholder route params","description":"<!-- https://linear.app/vercel/issue/NSEC-747 -->\r\n\r\nSelf-hosted Next.js applications served with `next start` and built with `cacheComponents: true` but without Partial Prefetching accept a request-supplied route param value as a prerender placeholder. One unauthenticated GET request can poison the fallback shell cache entry that a family of routes shares.\r\n\r\nSuch a route is served from a shell that keeps its never-prerenderable params as placeholders, so every value of those params shares one cache entry. A path segment equal to the percent-encoded, bracketed name of its own route param is treated as an unresolved placeholder, and only that param is deferred. A layout above it then renders its concrete value into the shell during the blocking render, and the result, including its HTTP status, is stored under the shared key.\r\n\r\nDepending on the application, the stored entry is one of the following:\r\n\r\n- A persistent 404, when the layout rejects the value with `notFound()`: served to every URL under the shell key with `\"revalidate\": false`, across server restarts, with no error logged.\r\n- A substituted param value, when the layout renders the value: the server-rendered HTML renders the attacker's value for that param in place of the visitor's own. A JavaScript client corrects it on hydration. No markup or script injection is possible, and no data is disclosed.\r\n\r\n### Preconditions\r\n\r\n1. `cacheComponents: true` with `partialPrefetching` unset or `false`.\r\n2. Self-hosted serving with `next start`.\r\n3. A dynamic route with a prerenderable param (`generateStaticParams`) whose requested value was not generated at build time.\r\n4. At least two never-prerenderable params below it: a layout reading the shallower one inside a Suspense boundary, and a deeper one the request supplies as the placeholder.\r\n5. A blocking fallback shell.\r\n\r\n### Workarounds\r\n\r\nSet `partialPrefetching: true` in `next.config`. Otherwise, apps should upgrade to the patched version as soon as possible.","summary":"Self-hosted Next.js apps built with cacheComponents and without Partial Prefetching can have a shared fallback shell cache entry poisoned by one unauthenticated GET request with a crafted path segment. The poisoned entry can serve a persistent 404 to every URL under that shell, or show an attacker-chosen param value in server-rendered HTML.","severity":"medium","cvss":6.3,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"next","fixed":["16.4.5"],"affected":">= 16.4.0, <= 16.4.4","ecosystem":"npm"}],"ecosystems":["npm"],"tags":["next.js","node","runtime","self-hosted"],"not_affected_if":["default-config","managed-hosting","partial-prefetching-enabled"],"how_to_check":"- Check the installed version with `npm ls next` and confirm whether it falls within `16.4.0` to `16.4.4`.\n- Look in `next.config` for `cacheComponents: true` and confirm `partialPrefetching` is unset or `false`.\n- Confirm the app is served with `next start` rather than a managed host.","fix":"- Upgrade `next` to `16.4.5`.\n- Workaround from the advisory: set `partialPrefetching: true` in `next.config`.","status":"open","published_at":"2026-11-03T18:39:43+00:00","first_seen_at":"2026-11-09T22:53:13+00:00","triaged_at":"2026-11-09T22:54:52+00:00","updated_at":"2026-11-09T22:54:52+00:00","category":"runtime","confidence":0.8,"triage":{"at":"2026-11-09T22:54:52Z","model":"claude-haiku-5-5","output":{"fix":"- Upgrade `next` to `16.4.5`.\n- Workaround from the advisory: set `partialPrefetching: true` in `next.config`.","reach":"internet","title":"Next.js: request-supplied route params can poison shared cache and serve persistent 404s","impact":"medium","summary":"Self-hosted Next.js apps built with cacheComponents and without Partial Prefetching can have a shared fallback shell cache entry poisoned by one unauthenticated GET request with a crafted path segment. The poisoned entry can serve a persistent 404 to every URL under that shell, or show an attacker-chosen param value in server-rendered HTML.","audience":"developers","category":"runtime","nicknames":[],"who_cares":["next.js","self-hosted","node"],"confidence":0.8,"fix_status":"available","needs_auth":"no","worst_case":"Persistent 404 served to all URLs under a shell, or attacker-chosen param value rendered in HTML","analyst_note":"","how_to_check":"- Check the installed version with `npm ls next` and confirm whether it falls within `16.4.0` to `16.4.4`.\n- Look in `next.config` for `cacheComponents: true` and confirm `partialPrefetching` is unset or `false`.\n- Confirm the app is served with `next start` rather than a managed host.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["managed-hosting","default-config","partial-prefetching-enabled"],"who_is_affected":"Self-hosted Next.js applications running `next start` with `cacheComponents: true` and Partial Prefetching off. The exposure requires a dynamic route with a prerenderable param, at least two never-prerenderable params below it, and a blocking fallback shell. Apps on managed hosting, apps without cacheComponents, or apps with Partial Prefetching enabled are not described as affected.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"medium"},"cost_usd":0.000865,"input_tokens":5169,"output_tokens":696,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'-119350':19A,27A '-2026':18A,26A '1':315C '2':323C '3':331C '4':349C '404':73B,238C '46vf':24A '5':379C 'accept':111C 'across':258C 'app':39B,391C 'applic':97C,227C 'attack':84B,282C 'attacker-chosen':83B 'block':209C,381C 'boundari':368C 'bracket':176C 'build':347C 'built':40B,103C 'cach':1A,8A,53B,132C,165C 'cachecompon':42B,105C,316C 'chosen':85B 'client':297C 'compon':9A 'concret':202C 'correct':298C 'craft':63B 'cve':17A,25A 'data':311C 'deeper':371C 'defer':194C 'depend':224C 'disclos':313C 'dynam':333C 'encod':175C 'entri':54B,68B,133C,166C,230C 'equal':170C 'error':263C 'everi':75B,158C,249C 'fallback':5A,51B,130C,382C 'fals':257C,322C 'famili':136C 'follow':235C 'generat':345C 'generatestaticparam':339C 'get':59B,125C 'ghsa':21A 'ghsa-vvgp-ww4w-46vf':20A 'host':34B,37B,95C,326C 'html':92B,279C 'http':216C 'hydrat':301C 'includ':214C 'inject':306C 'insid':365C 'javascript':296C 'keep':149C 'key':223C,254C 'layout':196C,241C,271C,360C 'least':351C 'log':264C 'markup':303C 'name':177C 'never':152C,354C 'never-prerender':151C,353C 'next':28A,100C,329C 'next.config':389C 'next.js':29B,38B,96C 'node':30B 'notfound':246C 'one':57B,123C,164C,232C,364C,372C 'otherwis':390C 'param':16A,86B,117C,154C,162C,182C,192C,267C,287C,338C,356C 'partial':45B,109C 'partialprefetch':319C,386C 'patch':396C 'path':64B,168C 'percent':174C 'percent-encod':173C 'persist':72B,237C 'place':289C 'placehold':14A,122C,156C,188C,378C 'poison':2A,55B,67B,128C 'possibl':308C,401C 'precondit':314C 'prefetch':46B,110C 'prerend':121C 'prerender':153C,337C,355C 'read':361C 'reject':242C 'render':91B,200C,210C,272C,278C,280C 'request':12A,60B,114C,126C,341C,374C 'request-suppli':11A,113C 'restart':260C 'result':213C 'revalid':256C 'rout':15A,116C,138C,142C,181C,334C 'runtim':31B 'script':305C 'segment':65B,169C 'self':33B,36B,94C,325C 'self-host':32B,35B,93C,324C 'serv':70B,98C,144C,247C,327C 'server':90B,259C,277C 'server-rend':89B,276C 'set':385C 'shallow':363C 'share':4A,50B,139C,163C,222C 'shell':6A,52B,79B,131C,147C,206C,253C,383C 'show':81B 'soon':399C 'start':101C,330C 'status':217C 'store':219C,229C 'substitut':266C 'suppli':13A,115C,375C 'suspens':367C 'time':348C 'treat':184C 'true':106C,317C,387C 'two':352C 'unauthent':58B,124C 'unresolv':187C 'unset':320C 'upgrad':393C 'url':76B,250C 'valu':87B,118C,159C,203C,244C,268C,274C,284C,342C 'version':397C 'via':10A 'visitor':292C 'vvgp':22A 'whose':340C 'without':44B,108C 'workaround':384C 'ww4w':23A","nicknames":[],"mitigations":[],"who_affected":"Self-hosted Next.js applications running `next start` with `cacheComponents: true` and Partial Prefetching off. The exposure requires a dynamic route with a prerenderable param, at least two never-prerenderable params below it, and a blocking fallback shell. Apps on managed hosting, apps without cacheComponents, or apps with Partial Prefetching enabled are not described as affected.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["next"],"ptokens":["next"],"labels":["medium","nextjs","node","npm","runtime","selfhosted"],"campaign_type":null,"search_a":"'-119350':19A,27A '-2026':18A,26A '46vf':24A 'cach':1A,8A 'compon':9A 'cve':17A,25A 'fallback':5A 'ghsa':21A 'ghsa-vvgp-ww4w-46vf':20A 'next':28A 'param':16A 'placehold':14A 'poison':2A 'request':12A 'request-suppli':11A 'rout':15A 'share':4A 'shell':6A 'suppli':13A 'via':10A 'vvgp':22A 'ww4w':23A","search_b":"'404':73B 'app':39B 'attack':84B 'attacker-chosen':83B 'built':40B 'cach':53B 'cachecompon':42B 'chosen':85B 'craft':63B 'entri':54B,68B 'everi':75B 'fallback':51B 'get':59B 'host':34B,37B 'html':92B 'next.js':29B,38B 'node':30B 'one':57B 'param':86B 'partial':45B 'path':64B 'persist':72B 'poison':55B,67B 'prefetch':46B 'render':91B 'request':60B 'runtim':31B 'segment':65B 'self':33B,36B 'self-host':32B,35B 'serv':70B 'server':90B 'server-rend':89B 'share':50B 'shell':52B,79B 'show':81B 'unauthent':58B 'url':76B 'valu':87B 'without':44B","search_c":"'1':315C '2':323C '3':331C '4':349C '404':238C '5':379C 'accept':111C 'across':258C 'app':391C 'applic':97C,227C 'attack':282C 'block':209C,381C 'boundari':368C 'bracket':176C 'build':347C 'built':103C 'cach':132C,165C 'cachecompon':105C,316C 'client':297C 'concret':202C 'correct':298C 'data':311C 'deeper':371C 'defer':194C 'depend':224C 'disclos':313C 'dynam':333C 'encod':175C 'entri':133C,166C,230C 'equal':170C 'error':263C 'everi':158C,249C 'fallback':130C,382C 'fals':257C,322C 'famili':136C 'follow':235C 'generat':345C 'generatestaticparam':339C 'get':125C 'host':95C,326C 'html':279C 'http':216C 'hydrat':301C 'includ':214C 'inject':306C 'insid':365C 'javascript':296C 'keep':149C 'key':223C,254C 'layout':196C,241C,271C,360C 'least':351C 'log':264C 'markup':303C 'name':177C 'never':152C,354C 'never-prerender':151C,353C 'next':100C,329C 'next.config':389C 'next.js':96C 'notfound':246C 'one':123C,164C,232C,364C,372C 'otherwis':390C 'param':117C,154C,162C,182C,192C,267C,287C,338C,356C 'partial':109C 'partialprefetch':319C,386C 'patch':396C 'path':168C 'percent':174C 'percent-encod':173C 'persist':237C 'place':289C 'placehold':122C,156C,188C,378C 'poison':128C 'possibl':308C,401C 'precondit':314C 'prefetch':110C 'prerend':121C 'prerender':153C,337C,355C 'read':361C 'reject':242C 'render':200C,210C,272C,278C,280C 'request':114C,126C,341C,374C 'request-suppli':113C 'restart':260C 'result':213C 'revalid':256C 'rout':116C,138C,142C,181C,334C 'script':305C 'segment':169C 'self':94C,325C 'self-host':93C,324C 'serv':98C,144C,247C,327C 'server':259C,277C 'server-rend':276C 'set':385C 'shallow':363C 'share':139C,163C,222C 'shell':131C,147C,206C,253C,383C 'soon':399C 'start':101C,330C 'status':217C 'store':219C,229C 'substitut':266C 'suppli':115C,375C 'suspens':367C 'time':348C 'treat':184C 'true':106C,317C,387C 'two':352C 'unauthent':124C 'unresolv':187C 'unset':320C 'upgrad':393C 'url':250C 'valu':118C,159C,203C,244C,268C,274C,284C,342C 'version':397C 'visitor':292C 'whose':340C 'without':108C 'workaround':384C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-11-03T18:39:43+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-vvgp-ww4w-46vf","url":"https://github.com/vercel/next.js/security/advisories/GHSA-vvgp-ww4w-46vf","severity":"medium","published_at":"2026-11-03T18:39:43+00:00","modified_at":"2026-11-06T10:20:17+00:00","first_seen_at":"2026-11-09T22:53:13+00:00","fetched_at":"2026-11-09T22:53:13+00:00","note":null}],"documents":[{"id":110391,"url":"https://github.com/vercel/next.js/security/advisories/GHSA-vvgp-ww4w-46vf","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":null,"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"}