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 - date manipulation routines (language initialization)

DESCRIPTION

This module is a series of routines, one per language, used to initialize the support for different languages in Date::Manip

ADDING A LANGUAGE

Adding a language is easily done. If you want to add a language, refer to the files in module that live in: lib/Date/Manip/Lang .

First, send me the name of the language (in ASCII character) as well as any locale designations.

For example, to create a Spanish translation (which is not necessary since it already exists), I need the following list::

spanish es es_es

The first word is the name of the language. Copy copy the english.pm file to spanish.pm.

The language file you just created is a new module containing the data for that language. It needs to be modified in the following ways:

  • Change "english" to "spanish" everywhere it appears in the new file. Also change "English" to "Spanish".

  • Look for a line of the form:

    @Encodings = qw();

    and change it to include the encodings most often used by this language. For example,

    @Encodings = qw(utf-8 iso-8859-1 perl);

    Always include 'utf-8' and 'perl' as the first and last elements in the list.

  • Change all of the data (after the __DATA__ line) as described below.

The data section of the module (which is written in YAML) is fairly straightforward to translate.

Where possible, please store all data in UTF-8 characters. If you have to escape high-byte characters, or use some other character encoding, please let me know. I'll do my best to deal with it, but it will delay me incorporating the translation into the module.

Most of the sections below can contain any number of alternate words which imply the same thing. Any time a list contains multiple words, the first should be the 'preferred' or most common word.

If a word contains UTF-8 characters which have a simple ASCII equivalent, you should include both forms. 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.

ampm

The ampm section consists of two lists of words. The first section are words which can be included after a time to designate a morning time (i.e. AM). The second set are words which designate an afternoon time (i.e. PM).

at

The word 'at' as it appears in the phrase:

AT 3:00
day_abb, day_char, day_name

These are each a list of seven elements which refer to the days Monday through Sunday.

day_char is typically a one or two character designation of the day (M, T, W, ...).

day_abb is an abbreviation for the day (Mon, Tue, Wed, ...).

day_name is the full day name (Monday, Tuesday, ...).

each

This is a list of words that could be used to translate the following phrases:

EACH Monday

EVERY Monday

EVERY month
fields

These are the names of the fields in a delta. There are 7 fields: years, months, weeks, days, hours, minutes, seconds.

The first field would be the ways that you might name the years field:

YEARS YEAR YRS YR
last

This is a list of words that could be used to translate the following phrase:

LAST day of the month
mode

This contains two lists of words which can be used to specify whether a delta is exact, approximate, or business.

The first list contains words which would specify exact or approximate deltas. In other words, a delta could be specified:

in EXACTLY 3 hours

in APPROXIMATELY 3 hours

The second list contains words which would specify business deltas. In other words:

in 3 BUSINESS days
month_abb, month_name

These specify the abbreviation and name respectively of the 12 months.

nextprev

This contains two sets of words. The first specifies the next element, and would be used to translate the following phrases:

NEXT week

NEXT Tuesday

The second set specifies the previous element, and would be used to translate the following phrases:

LAST Tuesday

PREVIOUS week
nth

This contains the numbers from 1-53. The first element should be the equivalent of '1st', '2nd', Additional elements should be the equivalent of the number spelled out (one, two, ...) and the ordinal number spelled out (first, second, ...).

of

This is a word which might be used to translate the following phrases:

1st dat OF December

1st day IN December
offset_date

This actually contains a hash, rather than a list.

Most languages have special words which refer to a day relative to today. The most common (in English) are:

TODAY
TOMORROW
YESTERDAY

The keys of the hash are the words, and the values of the hash are a delta which can be used to get the date relative to today.

For example, tomorrow is the delta '+0:0:0:1:0:0:0'.

If the word contains UTF-8 characters, please include it twice, once with the UTF-8 characters, and once as ASCII (if relevant).

offset_time

This is a hash similar to offset_date.

Most languages have words which might refer to times relative to the current time. In English, the only common word is

NOW

but in other languages, there may be other common words.

on

This is a word which might be used to translate the following phrases:

ON July 5th
times

This is a hash similar to offset_date.

Most languages have special words which refer to specific times of the day. In English, these include:

NOON
MIDNIGHT
when

This is two lists of words. The first list would be in a delta referring to a time in the past. For example:

5 hours AGO

5 hours EARLIER

The second list of words would be in a delta referring to a time in the future. For example:

IN 5 hours

5 hours LATER

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)