It's like discovering a hand-crank can jam — but only if someone feeds it a mile of ribbon
CVE-2026-60075 is a Regular Expression Denial of Service (ReDoS) in the Perl module Date::Manip through version 6.99. The vulnerable code path is _parse_time, which uses an unanchored substitution s/$timerx/ / where $timerx begins with a (?:$atrx|^|\s+) alternation. When a string containing a long run of whitespace (no actual time component needed) is passed to ParseDate(), Date::Manip::Date->parse(), or ->parse_time(), the regex engine retries the match at every whitespace position, backs track greedily across the rest, and produces quadratic CPU cost — a few kilobytes of spaces cost seconds, tens of kilobytes cost minutes. The impact is strictly availability: no code execution, no data leak.
The vendor CVSS of 7.5 HIGH (AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H) is *technically defensible in isolation* — if an attacker can send a crafted string over the network to a service that pipes it straight into ParseDate() without length limits, the DoS lands. In practice, however, this overstates reality. Date::Manip is a utility library embedded in Perl scripts and applications; the attacker can only reach the vulnerable regex through the *calling application*, and most callers either validate input length, parse trusted/internal data (logs, configs, cron expressions), or are not directly network-exposed. The EPSS of 0.00387 (~0.4%) confirms the community agrees exploitation at scale is unlikely. The score should be MEDIUM.
4 steps from start to impact.
Identify a network-exposed Perl application using Date::Manip
ParseDate(), Date::Manip::Date->parse(), or ->parse_time(). This is the gating prerequisite: Date::Manip is a library, not a daemon, so the attack surface is entirely defined by the calling application.- A Perl application reachable over the network
- That application passes attacker-controlled input to Date::Manip parsing functions
- Most Date::Manip usage is offline/internal (log analysis, cron, config parsing)
- Web frameworks in Perl (Dancer, Mojolicious, Catalyst) rarely delegate raw form input to Date::Manip without sanitization
- Perl's share of new web-facing deployments has been declining for over a decade
Craft a whitespace-heavy payload
' ' x 20000 in Perl, or equivalent. There is no complexity barrier; any script kiddie can produce this.- Ability to send an HTTP request or message containing a multi-KB string
- Many applications impose
Content-Lengthlimits or input validation that truncate the payload below the threshold needed for meaningful CPU burn - WAFs with request-body size limits may block oversized fields
Deliver payload to trigger quadratic backtracking
ParseDate() on the string, the unanchored substitution in _parse_time enters quadratic backtracking. CPU usage on that worker process spikes. For a 20 KB whitespace payload, parse time can exceed minutes on a single core.- Payload reaches the Date::Manip parsing call without truncation
- Impact is confined to the single process/thread handling the request — other workers/processes continue serving
- Process-level CPU limits (cgroups, ulimit, mod_perl timeout, PSGI timeout) will kill runaway workers
- Application-level timeouts in web servers (e.g., Apache
Timeout, Nginxproxy_read_timeout) often cap at 30-60 seconds
Sustain DoS via repeated requests
- Ability to send many concurrent requests
- Target has no rate-limiting or connection throttling
- Rate-limiting, CDN protections (Cloudflare, Akamai), and reverse-proxy connection limits reduce the attacker's throughput
- The blast radius is limited to the specific application process pool; no lateral movement, no data exfiltration, no privilege escalation
ParseDate(), ->parse(), or ->parse_time(): reject or truncate strings longer than 256 characters. No legitimate date string approaches this length. This eliminates the quadratic cost entirely. Deploy within the 365-day noisgate remediation SLA for MEDIUM findings, or sooner if your application directly parses untrusted input.RLimitCPU, systemd CPUQuota=, Starman/Plack timeouts). This bounds the blast radius of any single-request DoS.grep -rn 'ParseDate\|Date::Manip.*parse' /path/to/app to identify all call sites. Classify each as trusted-input or untrusted-input. Prioritize adding length guards on untrusted-input paths.- Upgrading Date::Manip — there is no patched version as of 2026-08-03. Version 6.99 is the latest and is vulnerable.
- Network-level rate limiting alone — while helpful, rate limiting does not prevent a single well-crafted request from burning CPU for minutes on the target worker. Input truncation at the application layer is necessary.
- Switching to
use re 'strict'— Perl's strict regex mode does not address quadratic backtracking in substitution patterns; it only catches certain compile-time regex errors.
The supporting signals.
| In-the-Wild Exploitation | None observed. Not listed on CISA KEV. No known campaigns or threat-actor usage. |
|---|---|
| Proof-of-Concept | No public PoC repository identified. However, reproduction is trivial: perl -MDate::Manip -e 'ParseDate(" " x 20000)' demonstrates the CPU burn. |
| EPSS Score | 0.00387 (~0.4%) — bottom quartile. The model rates exploitation probability as very low over the next 30 days. |
| KEV Status | Not listed. No CISA binding operational directive applies. |
| CVSS Vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H — 7.5 HIGH. Impact is availability-only (C:N/I:N/A:H). The AV:N rating assumes the library is reachable over the network, which depends on the calling application. |
| Affected Versions | Date::Manip ≤ 6.99 (all 6.xx releases). The module ships with many Linux distros as libdate-manip-perl (Debian/Ubuntu) or perl-Date-Manip (RHEL/Fedora). |
| Fixed Version | No fix released as of 2026-08-03. Version 6.99 (2026-03-02) is the latest on CPAN. The module has a single maintainer (SBECK). Workaround: truncate input before passing to parsing functions. |
| Scanning/Exposure Data | Date::Manip is not a network-listening service; Shodan/Censys/GreyNoise have no relevant exposure data. CPAN download stats show ~15,000 downloads/month, indicating moderate but not massive adoption. |
| Disclosure Date | 2026-07-30 — disclosed 4 days ago. |
| Researcher/Reporter | Not publicly attributed. Discovered via regex complexity analysis of the _parse_time substitution pattern. |
Sources.
Why this verdict
- Library indirection: The vulnerable code is in a library, not a daemon. Exploitation requires a calling application to pipe untrusted, unbounded input into
ParseDate()— this is not the common usage pattern for Date::Manip, which is predominantly used for internal date calculations, log parsing, and scripting. - Availability-only impact: Even in a successful exploitation, the blast radius is a single CPU-bound worker process. There is no memory corruption, no code execution, no confidentiality or integrity impact. Process supervisors, cgroups, and application timeouts naturally bound the damage.
- Role multiplier: Date::Manip is a general-purpose Perl date library. It is not canonically deployed in high-value roles (domain controllers, hypervisors, identity providers, backup systems, CI/CD). In its most common enterprise context — monitoring scripts, log processors, internal tools — a DoS of one worker thread has negligible fleet-wide impact. There is no plausible chain from this ReDoS to domain takeover, fleet compromise, or supply-chain pivot. The high-value role floor does not apply.
- EPSS confirmation: At 0.00387, the exploit prediction model places this in the bottom quartile, consistent with the assessment that real-world exploitation is unlikely.
- No patch available: While the lack of a patch is not itself a severity driver, it means defenders must rely on input-validation workarounds, which are straightforward for this specific pattern (truncate input length).
Why not higher?
The vendor's HIGH/7.5 rating assumes a deployment where untrusted network input flows directly into ParseDate() without length constraints. While *possible*, this represents a minority of Date::Manip installations. The impact is capped at availability of a single process — there is no escalation path to RCE, data exfiltration, or lateral movement. No KEV listing, no known exploitation, and an EPSS in the bottom quartile all argue against maintaining HIGH.
Why not lower?
Despite the friction, the vulnerability *is* real and trivially reproducible with zero authentication. Some Perl web applications do pass form-field input into date-parsing routines, and a determined attacker could sustain application-layer DoS against such a target. The lack of a vendor patch means there is no simple remediation path, only workarounds. LOW would understate the risk for the subset of deployments where Date::Manip does touch untrusted input.
Crowdsourced verification payload.
Run this script on any host where Date::Manip is installed. It checks the installed version via CPAN metadata. No special privileges required. Example: bash check_cve_2026_60075.sh
#!/usr/bin/env bash
# check_cve_2026_60075.sh
# Checks whether the installed Date::Manip version is vulnerable to CVE-2026-60075
# (ReDoS in _parse_time, affects all versions through 6.99)
# Run on target host. No elevated privileges needed.
set -euo pipefail
MODULE="Date::Manip"
FIXED_VERSION="7.00" # No fix released yet; 7.00 is hypothetical next major
# Check if perl is installed
if ! command -v perl &>/dev/null; then
echo "UNKNOWN - perl not found on this host"
exit 2
fi
# Get installed version
INSTALLED=$(perl -MDate::Manip -e 'print $Date::Manip::VERSION' 2>/dev/null || true)
if [ -z "$INSTALLED" ]; then
echo "UNKNOWN - Date::Manip is not installed"
exit 2
fi
# Compare versions using perl's version comparison
IS_VULN=$(perl -e '
use version;
my $installed = version->parse("'"$INSTALLED"'");
my $fixed = version->parse("'"$FIXED_VERSION"'");
print($installed < $fixed ? "yes" : "no");
' 2>/dev/null || echo "error")
if [ "$IS_VULN" = "yes" ]; then
echo "VULNERABLE - Date::Manip $INSTALLED is installed (affected: <= 6.99, no patch available)"
exit 1
elif [ "$IS_VULN" = "no" ]; then
echo "PATCHED - Date::Manip $INSTALLED is installed (>= $FIXED_VERSION)"
exit 0
else
echo "UNKNOWN - could not determine version status (installed: $INSTALLED)"
exit 2
fi