fix(core): avoid caching missing locale data

Only cache locale data loaded from the global locale registry when an actual locale entry is found.

This prevents attacker-controlled missing locale identifiers from being retained indefinitely in SSR when locale lookup falls back to a parent locale or the built-in English locale, avoiding unbounded process memory growth in locale-aware pipes and formatters.
This commit is contained in:
SkyZeroZx
2026-06-14 13:28:02 -05:00
committed by Jessica Janiuk
parent 417a4071a7
commit 98f42eaaae
2 changed files with 20 additions and 1 deletions
+10 -1
View File
@@ -104,11 +104,20 @@ export function getLocalePluralCase(locale: string): (value: number) => number {
*/
export function getLocaleData(normalizedLocale: string): any {
if (!(normalizedLocale in LOCALE_DATA)) {
LOCALE_DATA[normalizedLocale] =
const globalLocaleData =
global.ng &&
global.ng.common &&
global.ng.common.locales &&
global.ng.common.locales[normalizedLocale];
// Only cache global locale data when an entry is actually found, to avoid
// caching missing lookups. In SSR this cache is process-wide across requests,
// so caching `undefined` would retain attacker-controlled locale identifiers
// indefinitely. It would also make the `in` check above short-circuit on
// subsequent lookups and skip the global fallback.
if (globalLocaleData !== undefined) {
LOCALE_DATA[normalizedLocale] = globalLocaleData;
}
return globalLocaleData;
}
return LOCALE_DATA[normalizedLocale];
}
@@ -85,6 +85,16 @@ describe('locale data api', () => {
expect(findLocaleData('de-CH')).toEqual(localeDeCH);
});
it('should not cache missing global locale data lookups', () => {
const localeEnNZ: any[] = ['en-NZ'];
expect(findLocaleData('en-NZ')).toEqual(localeEn);
global.ng.common.locales['en-nz'] = localeEnNZ;
expect(findLocaleData('en-NZ')).toBe(localeEnNZ);
});
it('should find the parent LOCALE_DATA if the exact locale is not available and the parent locale is on the global object', () => {
expect(findLocaleData('de-BE')).toEqual(localeDe);
});