Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 15 additions & 1 deletion packages/common/src/i18n/format_number.ts
Original file line number Diff line number Diff line change
Expand Up @@ -8,14 +8,14 @@

import {ɵRuntimeError as RuntimeError} from '@angular/core';

import {RuntimeErrorCode} from '../errors';
import {
getLocaleNumberFormat,
getLocaleNumberSymbol,
getNumberOfCurrencyDigits,
NumberFormatStyle,
NumberSymbol,
} from './locale_data_api';
import {RuntimeErrorCode} from '../errors';

export const NUMBER_FORMAT_REGEXP = /^(\d+)?\.((\d+)(-(\d+))?)?$/;
const MAX_DIGITS = 22;
Expand Down Expand Up @@ -77,6 +77,20 @@ function formatNumberToLocaleString(
} else if (minFractionPart != null && minFraction > maxFraction) {
maxFraction = minFraction;
}

// Prevent DoS via resource exhaustion by capping the maximum padding iterations
const MAX_ALLOWED_DIGITS = 100;
if (
minInt > MAX_ALLOWED_DIGITS ||
minFraction > MAX_ALLOWED_DIGITS ||
maxFraction > MAX_ALLOWED_DIGITS
) {
throw new RuntimeError(
RuntimeErrorCode.INVALID_DIGIT_INFO,
ngDevMode &&
`${digitsInfo} is not a valid digit info. Exceeded maximum limits of ${MAX_ALLOWED_DIGITS} digits.`,
);
}
}

roundNumber(parsedNumber, minFraction, maxFraction);
Expand Down
14 changes: 13 additions & 1 deletion packages/common/test/i18n/format_number_spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@
* found in the LICENSE file at https://angular.dev/license
*/

import {ɵDEFAULT_LOCALE_ID, ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core';
import {formatCurrency, formatNumber, formatPercent} from '../../index';
import localeAr from '../../locales/ar';
import localeEn from '../../locales/en';
import localeEsUS from '../../locales/es-US';
import localeFr from '../../locales/fr';
import {ɵDEFAULT_LOCALE_ID, ɵregisterLocaleData, ɵunregisterLocaleData} from '@angular/core';

describe('Format number', () => {
beforeAll(() => {
Expand Down Expand Up @@ -43,6 +43,18 @@ describe('Format number', () => {
/is higher than the maximum/,
);
});

it('should throw if minInt, minFraction, or maxFraction exceeds 100 to prevent DoS', () => {
const expectedError = /Exceeded maximum limits of 100 digits/;
expect(() => formatNumber(1.1, ɵDEFAULT_LOCALE_ID, '101.4-5')).toThrowError(expectedError);
expect(() => formatNumber(1.1, ɵDEFAULT_LOCALE_ID, '3.101-105')).toThrowError(
expectedError,
);
expect(() => formatNumber(1.1, ɵDEFAULT_LOCALE_ID, '3.4-101')).toThrowError(expectedError);
expect(() => formatNumber(1.1, ɵDEFAULT_LOCALE_ID, '1.2000000000-20000000')).toThrowError(
expectedError,
);
});
});

describe('transform with custom locales', () => {
Expand Down
Loading