Security Advisories (2)
CVE-2026-60074 (2026-07-30)

Date::Manip versions through 6.99 for Perl return corrupted dates via non-ASCII decimal digits that pass the numeric range tests in check. The parse regexes capture year, month and day with the `\d` shorthand, which on a character string matches the whole Unicode decimal digit property `\p{Nd}` and not just `[0-9]`. Date::Manip::Base::check then validates the captured fields with numeric comparisons alone (`$y<1 || $y>9999`, `$m<1 || $m>12`, `$d<1 || $d>$days`), and _parse_check stores the numified fields (`$y+0`). Perl truncates a string at the first character that is not an ASCII digit, so a field whose leading characters are ASCII digits numifies to an in-range prefix and satisfies every test: a year field of three ASCII digits followed by U+0664 ARABIC-INDIC DIGIT FOUR numifies to 202, giving the year 0202, and one non-ASCII digit in the month or day field shifts those fields the same way. The hour, minute and second fields match explicit ASCII character classes (`0?[0-9]`, `[0-5][0-9]`) and do not shift, though a non-ASCII digit in a fractional hour or minute field truncates the fraction. Any caller that passes an untrusted character string to ParseDate() or Date::Manip::Date->parse() can get back a date that differs from the string it parsed, with no parse error. Where the parsed date gates logic such as an expiry check or a retention window, the shift goes unnoticed.

CVE-2026-60075 (2026-07-30)

Date::Manip versions through 6.99 for Perl allow CPU exhaustion via quadratic backtracking in the unanchored time substitution in _parse_time. _parse_time removes a time from anywhere in the string with the unanchored substitution `s/$timerx/ /`, where $timerx is an auto-generated alternation of time patterns reached through a leading `(?:$atrx|^|\s+)`. The engine therefore retries the match at every position of an interior whitespace run: at each start position the leading `\s+` consumes the rest of the run greedily, the time alternation fails because the run holds no digits, and the engine backtracks a space at a time across the run before advancing the start position, which is quadratic in the length of the run. No time need be present in the string for this to happen, only a long run of whitespace, and the parse time rises about fourfold for each doubling of the run: a few kilobytes of whitespace costs seconds of CPU per parse and tens of kilobytes costs minutes. Any caller that passes an untrusted string of unbounded length to ParseDate(), Date::Manip::Date->parse() or ->parse_time() can be made to spend unbounded CPU in a single parse, a denial of service.

NAME

Date::Manip::Lang - language support for Date::Manip

DESCRIPTION

Date::Manip supports a number of different languages when parsing dates, and more can be added.

CURRENT LANGUAGES

Currently, the following languages are supported by Date::Manip. The version of Date::Manip where they were added is included (so you can see the minimum version of Date::Manip needed to parse each).

The language can be chosen by setting the Language config variable to the name of the language or any of the aliases included in the table.

All names and aliases are case insensitive.

Language     Version  Aliases

English      default  en, en_us

Catalan      5.43     ca
Danish       5.41     da
Dutch        5.32     Nederlands, nl
Finnish      6.31     fi, fi_fi
French       5.02     fr, fr_fr
German       5.31     de, de_de
Italian      5.35     it, it_it
Norwegian    6.21     nb, nb_no
Polish       5.32     pl, pl_pl
Portuguese   5.34     pt, pt_pt
Romanian     5.35     ro, ro_ro
Russian      5.41     ru, ru_ru
Spanish      5.33     es, es_es
Swedish      5.05     sv
Turkish      5.41     tr, tr_tr

ADDING A LANGUAGE

Adding a language is easily done (if you're fluent in both English and the other language). If you want to add a new language, do the following:

Language name

When you submit the new language, I'll need the name of the language (of course) and any common locale names that might be useful for people to select the language.

For example, if you were creating a Spanish translation (which is not necessary since it already exists), I would need the following list:

spanish es es_es
Copy the english module

Copy the english.pm file (which is in lib/Date/Manip/Lang in the Date::Manip distribution) to the new language (i.e. spanish.pm in this example).

Set some variables in the new module

The new module (spanish.pm) will need a few simple modifications. Change the package name from 'english' to 'spanish'.

Fix the @Encodings lines. Most languages can be written in more than one encoding. The first encoding in the list should be utf-8 and the last should be perl. Include any other encodings that should be supported as well.

Set the $YearAdded and $LangName appropriately.

Translate the language terms

The data section of the module is fairly straightforward to translate.

Every term is defined in the Date::Manip::Lang::english document (or in any of the other language module documents), so please refer to it to find out what each element means. Then replace the English version with the new translation.

There are some requirements:

1) Every element should be defined (except for the sephm and sepms elements which are optional).

2) The module must be written using UTF-8 characters if the language includes any non-ASCII characters.

3) Each element includes a list of values (different variations of the element). In most cases, the order of the values for each element is not important since they are just used to create a regular expression for parsing dates, but a few of them are also used to determine printable values using the Date::Manip::Date::printf method (or the UnixDate function). These elements are:

Element       printf directive

ampm          %p
day_abb       %a
day_char      %v
day_name      %A
month_abb     %b
month_name    %B
nth           %E

For each of these, the value that should be printed out must be the first value in the list.

4) When possible, if a language includes characters that are essentially ASCII characters with a punctuation mark, please include a variation of the value which is just ASCII with the punctuation removed. For example, the spanish name for Saturday in ASCII would be written sabado, but in reality, the first 'a' has an accent over it. This word should appear twice... first in full UTF-8 encoding, and second as all ASCII. If the language (Russian for example) has no ASCII equivalent, just include the UTF-8 representation.

Feel free to contact me if you have any questions.

LANGUAGE SPECIFIC RULES

In the language file, there is one special value named _special_rules. This is a hash of special parsing rules that will be applied for this language.

Currently the following rules are available:

remove_trailing_period

If this is set, trailing periods will be removed.

For example, in German, default output of the date command includes a day of month with a trailing period. For example:

Mo 3. Jan 11:00:00 EST 2022

If this rule is set, periods followed by whitespace (or an end of string) are stripped.

remove_parens

This will strip parentheses () from a string.

strip_word

This is a list of words that will be stripped from a string. Each word must be bracketed by the start/end of the string or whitespace.

SEE ALSO

Date::Manip - main module documentation

LICENSE

This script is free software; you can redistribute it and/or modify it under the same terms as Perl itself.

AUTHOR

Sullivan Beck (sbeck@cpan.org)