Skip to content

Commit

Permalink
[i18n] Routing fix (#70761)
Browse files Browse the repository at this point in the history
This fixes a bug where an incorrectly sanitized query parameter would
cause an invalid routing condition resulting in the wrong route being
served to users. This currently requires some specific edge conditions
in order to trigger such as missing i18n configuration, self-hosted,
specifically crafted query parameter, and a path-based middleware for
authorization.
  • Loading branch information
wyattjoh authored Oct 3, 2024
1 parent 214c0a0 commit d0cbe64
Show file tree
Hide file tree
Showing 3 changed files with 44 additions and 0 deletions.
8 changes: 8 additions & 0 deletions packages/next/src/server/base-server.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1017,6 +1017,14 @@ export default abstract class Server<
req.headers['x-forwarded-proto'] ??= isHttps ? 'https' : 'http'
req.headers['x-forwarded-for'] ??= originalRequest?.socket?.remoteAddress

// Validate that if i18n isn't configured or the passed parameters are not
// valid it should be removed from the query.
if (!this.i18nProvider?.validateQuery(parsedUrl.query)) {
delete parsedUrl.query.__nextLocale
delete parsedUrl.query.__nextDefaultLocale
delete parsedUrl.query.__nextInferredLocaleFromDefault
}

// This should be done before any normalization of the pathname happens as
// it captures the initial URL.
this.attachRequestMeta(req, parsedUrl)
Expand Down
31 changes: 31 additions & 0 deletions packages/next/src/server/lib/i18n-provider.ts
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,37 @@ export class I18NProvider {
}
}

/**
* Validates that the locale is valid.
*
* @param locale The locale to validate.
* @returns `true` if the locale is valid, `false` otherwise.
*/
private validate(locale: string): boolean {
return this.lowerCaseLocales.includes(locale.toLowerCase())
}

/**
* Validates that the locales in the query object are valid.
*
* @param query The query object to validate.
* @returns `true` if the locale is valid, `false` otherwise.
*/
public validateQuery(query: NextParsedUrlQuery) {
if (query.__nextLocale && !this.validate(query.__nextLocale)) {
return false
}

if (
query.__nextDefaultLocale &&
!this.validate(query.__nextDefaultLocale)
) {
return false
}

return true
}

/**
* Analyzes the pathname for a locale and returns the pathname without it.
*
Expand Down
5 changes: 5 additions & 0 deletions packages/next/src/server/lib/router-utils/resolve-routes.ts
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,11 @@ export function getResolveRoutes(
parsedUrl.pathname = maybeAddTrailingSlash(parsedUrl.pathname)
}
}
} else {
// As i18n isn't configured we remove the locale related query params.
delete parsedUrl.query.__nextLocale
delete parsedUrl.query.__nextDefaultLocale
delete parsedUrl.query.__nextInferredLocaleFromDefault
}

const checkLocaleApi = (pathname: string) => {
Expand Down

0 comments on commit d0cbe64

Please sign in to comment.