{"id":"GHSA-w7gw-66vg-99gq","kind":"vulnerability","aliases":["GHSA-w7gw-66vg-99gq"],"related":[],"title":"`getRouterParam` from `nuxt/server` can return a different param from the one h3 matched when the path contains `%3F`","description":"## Impact\r\n\r\n`getRouterParam` and `getRouterParams` from `nuxt/server` return the route params that h3 matched, with their original percent-encoding preserved. To do so, they line up the raw request URL with the decoded path h3 routed on.\r\n\r\nWhen a path segment contained an encoded question mark (`%3F`), h3 routed on the decoded path only up to that `?`, but the raw URL was not cut at the same point. The helpers then read params from the wrong segments, so they could return a different value from the one h3 matched in `event.context.params`. Named (`[id]`), unnamed and catch-all (`[...slug]`) params are affected.\r\n\r\nFor example, with `server/api/auth/[...slug].get.ts`, a request to `/api/auth/private%3Fignored/public` is matched by h3 with `slug` set to `private`, while `getRouterParam(event, 'slug', { decode: true })` returned `public`.\r\n\r\nAn application is affected if it uses the Nuxt helper for one decision (such as an authorization check) and h3's matched params, or another source, for another (such as selecting the resource). In that case a request can pass the check for one resource and act on another.\r\n\r\n## Mitigating factors\r\n\r\n- Exploitation requires an application that reads the same route param from two different sources and relies on them agreeing. Applications that read params only through `getRouterParam(s)` from `nuxt/server`, or only through `event.context.params` / h3's helpers, are not affected.\r\n- The helpers were introduced in `4.6.0`. Earlier releases and Nuxt 3 are not affected.\r\n\r\n## Affected versions\r\n\r\n`nuxt` and `@nuxt/nitro-server` `>=4.6.0 <4.6.2`.\r\n\r\n## Patches\r\n\r\nFixed in `nuxt@4.6.2`. The helpers now rebuild params from exactly the path h3 routed on, and check that each value decodes to the param h3 matched. If any value does not, they return h3's params unchanged, so they can only return a different encoding of h3's match, never a different value.\r\n\r\n## Workarounds\r\n\r\nUpgrade to `nuxt@4.6.2`. If you cannot upgrade:\r\n\r\n1. Read a route param from a single source for both the check and the lookup.\r\n2. Alternatively, reject requests whose path contains `%3F` in a server middleware.\r\n\r\n## References\r\n\r\n- [Server imports documentation](https://nuxt.com/docs/4.x/guide/going-further/server-imports)","summary":"The getRouterParam and getRouterParams helpers in nuxt/server can return a different path segment than the one h3 matched when a request path contains an encoded question mark (%3F). An application that checks authorization with one param source and looks up a resource with another can pass the check for one resource and act on a different one.","severity":"low","cvss":3.7,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"nuxt","note":">= 4.6.0 < 4.6.2","fixed":["4.6.2"],"affected":"","ecosystem":"npm"},{"name":"@nuxt/nitro-server","note":">= 4.6.0 < 4.6.2","fixed":["4.6.2"],"affected":"","ecosystem":"npm"}],"ecosystems":["npm"],"tags":["cwe-436","cwe-863","h3","nitro","nuxt","package","server-routes"],"not_affected_if":["below-4.6.0","no-route-param-auth-check","nuxt-3","single-param-source"],"how_to_check":"- Check the installed versions with `npm ls nuxt @nuxt/nitro-server`; affected if they are `>=4.6.0 <4.6.2`.\n- Search server routes for `getRouterParam` or `getRouterParams` used alongside `event.context.params` or another source for the same param, especially in authorization checks.\n- Note that Nuxt 3 and releases before `4.6.0` are not affected.","fix":"- nuxt `4.6.2`\n- @nuxt/nitro-server `4.6.2`","status":"open","published_at":"2026-10-16T18:58:57+00:00","first_seen_at":"2026-11-09T22:53:16+00:00","triaged_at":"2026-11-09T22:57:28+00:00","updated_at":"2026-11-09T22:57:28+00:00","category":"package","confidence":0.8,"triage":{"at":"2026-11-09T22:57:28Z","model":"claude-haiku-5-5","output":{"fix":"- nuxt `4.6.2`\n- @nuxt/nitro-server `4.6.2`","reach":"internet","title":"Nuxt: getRouterParam may return wrong route param on encoded question mark","impact":"medium","summary":"The getRouterParam and getRouterParams helpers in nuxt/server can return a different path segment than the one h3 matched when a request path contains an encoded question mark (%3F). An application that checks authorization with one param source and looks up a resource with another can pass the check for one resource and act on a different one.","audience":"developers","category":"package","nicknames":[],"who_cares":["nuxt","nitro","h3","server-routes"],"confidence":0.8,"fix_status":"available","needs_auth":"no","worst_case":"request passes a check, then acts on a different resource","analyst_note":"","how_to_check":"- Check the installed versions with `npm ls nuxt @nuxt/nitro-server`; affected if they are `>=4.6.0 <4.6.2`.\n- Search server routes for `getRouterParam` or `getRouterParams` used alongside `event.context.params` or another source for the same param, especially in authorization checks.\n- Note that Nuxt 3 and releases before `4.6.0` are not affected.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["nuxt-3","below-4.6.0","single-param-source","no-route-param-auth-check"],"who_is_affected":"Exposure requires a Nuxt 4 application (4.6.0 to 4.6.2) that reads the same route parameter from two different sources and relies on them agreeing, such as an authorization check via getRouterParam and a resource lookup via event.context.params. Applications that read params only through one source are not affected, and the helpers did not exist before 4.6.0.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"yes","severity_if_unknown":"low"},"cost_usd":0.001384,"input_tokens":5342,"output_tokens":1700,"severity_before":"low"},"analyst_status":null,"analyst_note":null,"search":"'-436':32B '-863':34B '/api/auth/private':210C '/docs/4.x/guide/going-further/server-imports)':438C '1':404C '2':420C '3':329C '3f':18A,69B,145C,427C '3fignored/public':211C '4.6.0':324C,338C '4.6.2':339C,344C,399C '66vg':22A,27A '99gq':23A,28A 'act':94B,275C 'affect':200C,232C,318C,332C,333C 'agre':298C 'altern':421C 'anoth':85B,253C,256C,277C 'applic':71B,230C,283C,299C 'author':74B,245C 'cannot':402C 'case':264C 'catch':195C 'catch-al':194C 'check':73B,89B,246C,270C,358C,416C 'contain':17A,64B,140C,426C 'could':178C 'cut':162C 'cwe':31B,33B 'decis':241C 'decod':131C,150C,225C,362C 'differ':7A,52B,97B,181C,292C,385C,393C 'document':435C 'earlier':325C 'encod':66B,117C,142C,386C 'event':223C 'event.context.params':189C,312C 'exact':351C 'exampl':202C 'exploit':280C 'factor':279C 'fix':341C 'get.ts':206C 'getrouterparam':1A,43B,45B,100C,102C,222C,305C 'ghsa':20A,25A 'ghsa-w7gw-66vg-99gq':19A,24A 'h3':12A,35B,58B,110C,133C,146C,186C,215C,248C,313C,354C,366C,375C,388C 'helper':46B,168C,238C,315C,320C,346C 'id':191C 'impact':99C 'import':434C 'introduc':322C 'line':123C 'look':80B 'lookup':419C 'mark':68B,144C 'match':13A,59B,111C,187C,213C,250C,367C,390C 'middlewar':431C 'mitig':278C 'name':190C 'never':391C 'nitro':36B 'nuxt':29A,37B,237C,328C,335C,343C,398C 'nuxt.com':437C 'nuxt.com/docs/4.x/guide/going-further/server-imports)':436C 'nuxt/nitro-server':30A,337C 'nuxt/server':3A,48B,104C,308C 'one':11A,57B,76B,91B,98B,185C,240C,272C 'origin':114C 'packag':38B 'param':8A,77B,108C,171C,198C,251C,289C,302C,349C,365C,377C,408C 'pass':87B,268C 'patch':340C 'path':16A,53B,63B,132C,138C,151C,353C,425C 'percent':116C 'percent-encod':115C 'point':166C 'preserv':118C 'privat':220C 'public':228C 'question':67B,143C 'raw':126C,158C 'read':170C,285C,301C,405C 'rebuild':348C 'refer':432C 'reject':422C 'releas':326C 'reli':295C 'request':62B,127C,208C,266C,423C 'requir':281C 'resourc':83B,92B,261C,273C 'return':5A,50B,105C,179C,227C,374C,383C 'rout':41B,107C,134C,147C,288C,355C,407C 'segment':54B,139C,175C 'select':259C 'server':40B,430C,433C 'server-rout':39B 'server/api/auth':204C 'set':218C 'singl':411C 'slug':197C,205C,217C,224C 'sourc':78B,254C,293C,412C 'true':226C 'two':291C 'unchang':378C 'unnam':192C 'upgrad':396C,403C 'url':128C,159C 'use':235C 'valu':182C,361C,370C,394C 'version':334C 'w7gw':21A,26A 'whose':424C 'workaround':395C 'wrong':174C","nicknames":[],"mitigations":[],"who_affected":"Exposure requires a Nuxt 4 application (4.6.0 to 4.6.2) that reads the same route parameter from two different sources and relies on them agreeing, such as an authorization check via getRouterParam and a resource lookup via event.context.params. Applications that read params only through one source are not affected, and the helpers did not exist before 4.6.0.","tier":"C","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"developers","plain_action":null,"pkeys":["nitroserver","nuxt"],"ptokens":["nitro","nuxt","server"],"labels":["cwe436","cwe863","h3","low","nitro","npm","nuxt","package","serverroutes"],"campaign_type":null,"search_a":"'3f':18A '66vg':22A,27A '99gq':23A,28A 'contain':17A 'differ':7A 'getrouterparam':1A 'ghsa':20A,25A 'ghsa-w7gw-66vg-99gq':19A,24A 'h3':12A 'match':13A 'nuxt':29A 'nuxt/nitro-server':30A 'nuxt/server':3A 'one':11A 'param':8A 'path':16A 'return':5A 'w7gw':21A,26A","search_b":"'-436':32B '-863':34B '3f':69B 'act':94B 'anoth':85B 'applic':71B 'author':74B 'check':73B,89B 'contain':64B 'cwe':31B,33B 'differ':52B,97B 'encod':66B 'getrouterparam':43B,45B 'h3':35B,58B 'helper':46B 'look':80B 'mark':68B 'match':59B 'nitro':36B 'nuxt':37B 'nuxt/server':48B 'one':57B,76B,91B,98B 'packag':38B 'param':77B 'pass':87B 'path':53B,63B 'question':67B 'request':62B 'resourc':83B,92B 'return':50B 'rout':41B 'segment':54B 'server':40B 'server-rout':39B 'sourc':78B","search_c":"'/api/auth/private':210C '/docs/4.x/guide/going-further/server-imports)':438C '1':404C '2':420C '3':329C '3f':145C,427C '3fignored/public':211C '4.6.0':324C,338C '4.6.2':339C,344C,399C 'act':275C 'affect':200C,232C,318C,332C,333C 'agre':298C 'altern':421C 'anoth':253C,256C,277C 'applic':230C,283C,299C 'author':245C 'cannot':402C 'case':264C 'catch':195C 'catch-al':194C 'check':246C,270C,358C,416C 'contain':140C,426C 'could':178C 'cut':162C 'decis':241C 'decod':131C,150C,225C,362C 'differ':181C,292C,385C,393C 'document':435C 'earlier':325C 'encod':117C,142C,386C 'event':223C 'event.context.params':189C,312C 'exact':351C 'exampl':202C 'exploit':280C 'factor':279C 'fix':341C 'get.ts':206C 'getrouterparam':100C,102C,222C,305C 'h3':110C,133C,146C,186C,215C,248C,313C,354C,366C,375C,388C 'helper':168C,238C,315C,320C,346C 'id':191C 'impact':99C 'import':434C 'introduc':322C 'line':123C 'lookup':419C 'mark':144C 'match':111C,187C,213C,250C,367C,390C 'middlewar':431C 'mitig':278C 'name':190C 'never':391C 'nuxt':237C,328C,335C,343C,398C 'nuxt.com':437C 'nuxt.com/docs/4.x/guide/going-further/server-imports)':436C 'nuxt/nitro-server':337C 'nuxt/server':104C,308C 'one':185C,240C,272C 'origin':114C 'param':108C,171C,198C,251C,289C,302C,349C,365C,377C,408C 'pass':268C 'patch':340C 'path':132C,138C,151C,353C,425C 'percent':116C 'percent-encod':115C 'point':166C 'preserv':118C 'privat':220C 'public':228C 'question':143C 'raw':126C,158C 'read':170C,285C,301C,405C 'rebuild':348C 'refer':432C 'reject':422C 'releas':326C 'reli':295C 'request':127C,208C,266C,423C 'requir':281C 'resourc':261C,273C 'return':105C,179C,227C,374C,383C 'rout':107C,134C,147C,288C,355C,407C 'segment':139C,175C 'select':259C 'server':430C,433C 'server/api/auth':204C 'set':218C 'singl':411C 'slug':197C,205C,217C,224C 'sourc':254C,293C,412C 'true':226C 'two':291C 'unchang':378C 'unnam':192C 'upgrad':396C,403C 'url':128C,159C 'use':235C 'valu':182C,361C,370C,394C 'version':334C 'whose':424C 'workaround':395C 'wrong':174C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-10-16T18:58:57+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-w7gw-66vg-99gq","url":"https://github.com/nuxt/nuxt/security/advisories/GHSA-w7gw-66vg-99gq","severity":"low","published_at":"2026-10-16T18:58:57+00:00","modified_at":"2026-10-29T13:29:52+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":50377,"url":"https://github.com/nuxt/nuxt/security/advisories/GHSA-w7gw-66vg-99gq","title":"Vendor advisory: github.com","kind":"vendor","source":"nvd","publisher":"vendor","text":null,"published_at":"2026-10-16T18:58:57+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"}