fix(common): Limits date format string length

Introduces a maximum length of 256 characters for date format strings.

This prevents potential Denial of Service (DoS) attacks by throwing an
`INVALID_DATE_FORMAT` error if an excessively long format string is
provided to `formatDate` or `DatePipe`, safeguarding against performance
degradation or application crashes.
This commit is contained in:
SkyZeroZx
2026-05-30 10:55:30 -05:00
committed by Andrew Scott
parent af7cb63151
commit eeb03f4ea3
3 changed files with 28 additions and 0 deletions
+12
View File
@@ -36,6 +36,7 @@ export const ISO8601_DATE_REGEX =
const NAMED_FORMATS: {[localeId: string]: {[format: string]: string}} = {};
const DATE_FORMATS_SPLIT =
/((?:[^BEGHLMOSWYZabcdhmswyz']+)|(?:'(?:[^']|'')*')|(?:G{1,5}|y{1,4}|Y{1,4}|M{1,5}|L{1,5}|w{1,2}|W{1}|d{1,2}|E{1,6}|c{1,6}|a{1,5}|b{1,5}|B{1,5}|h{1,2}|H{1,2}|m{1,2}|s{1,2}|S{1,3}|z{1,4}|Z{1,5}|O{1,4}))([\s\S]*)/;
const MAX_DATE_FORMAT_LENGTH = 256;
const enum ZoneWidth {
Short,
@@ -89,6 +90,7 @@ export function formatDate(
timezone?: string,
): string {
let date = toDate(value);
assertValidDateFormatLength(format);
const namedFormat = getNamedFormat(locale, format);
format = namedFormat || format;
@@ -132,6 +134,16 @@ export function formatDate(
return text;
}
function assertValidDateFormatLength(format: string) {
if (format.length > MAX_DATE_FORMAT_LENGTH) {
throw new RuntimeError(
RuntimeErrorCode.SUSPICIOUS_DATE_FORMAT,
ngDevMode &&
`Date format is too long. Exceeded maximum length of ${MAX_DATE_FORMAT_LENGTH} characters.`,
);
}
}
/**
* Asserts that the given date format is free from common mistakes. Throws an
* error if one is found (except for the case of all "Y", in which case we just
@@ -351,6 +351,16 @@ describe('Format date', () => {
});
});
it('should throw if the date format exceeds 256 characters to prevent DoS', () => {
const expectedError = /Exceeded maximum length of 256 characters/;
expect(() => formatDate(date, 'y'.repeat(257), ɵDEFAULT_LOCALE_ID)).toThrowError(
expectedError,
);
expect(() => formatDate(date, "'literal'".repeat(257), ɵDEFAULT_LOCALE_ID)).toThrowError(
expectedError,
);
});
it('should format invalid in IE ISO date', () =>
expect(formatDate('2017-01-11T12:00:00.014-0500', defaultFormat, ɵDEFAULT_LOCALE_ID)).toEqual(
'Jan 11, 2017',
@@ -77,6 +77,12 @@ describe('DatePipe', () => {
it('should give precedence to the passed in format', () =>
expect(pipe.transform('2017-01-11T10:14:39+0000', 'shortDate')).toEqual('1/11/17'));
it('should reject date formats that are too long', () => {
expect(() => pipe.transform(date, 'y'.repeat(257))).toThrowError(
/InvalidPipeArgument: 'NG02300: Date format is too long/,
);
});
it('should use format provided in component as default format when no format is passed in', () => {
@Component({
selector: 'test-component',