CVE-2026-87082 Overview
CVE-2026-87082 affects the Perl module Net::IDN::Punycode in versions before 2.590. The encode_punycode function fails to validate that its input is well-formed UTF-8. When a caller passes bytes with the UTF-8 flag set over malformed sequences, the encoder enters an infinite loop, crashes with SIGBUS, dies with a panic, or returns a Punycode label for a name the input never held. The defect exists in both the XS backend and the pure-Perl backend. The decoder is not affected. Applications that call encode_punycode directly on attacker-controlled bytes are exposed to denial of service and label confusion.
Critical Impact
A direct caller encoding attacker-supplied bytes hangs, crashes, or receives a Punycode label for an internationalized domain name (IDN) that the input never represented, enabling denial of service and potential label confusion in name-handling pipelines.
Affected Products
- Net::IDN::Encode (Perl distribution) versions before 2.590
- Net::IDN::Punycode XS backend on perl 5.32 and later (infinite loop)
- Net::IDN::Punycode pure-Perl backend on perl 5.28 and later (SIGBUS or panic)
Discovery Timeline
- 2026-09-22 - CVE-2026-87082 published to the National Vulnerability Database (NVD)
- 2026-09-22 - Vulnerability discussed on the Openwall OSS-Security list
- 2026-09-22 - Last updated in NVD database
Technical Details for CVE-2026-87082
Vulnerability Analysis
The vulnerability is an infinite loop and memory-safety defect classified as [CWE-835] (Loop with Unreachable Exit Condition). Neither backend of Net::IDN::Punycode verifies that its input is well-formed UTF-8 before scanning code points. The :utf8 PerlIO layer produces exactly such flagged-but-malformed strings from any malformed input, so untrusted bytes reach the encoder unchecked.
On perl 5.32 and later, the XS backend calls utf8_to_uvchr_buf, which reports a malformed sequence by returning a length of (STRLEN)-1. The scan pointer then steps backward one byte instead of forward, and the loop never terminates. On earlier perl releases, the same code path returns a valid Punycode label for a different domain name than the caller supplied. The pure-Perl backend runs a regex over the flagged string and, depending on the byte pattern, aborts with SIGBUS on perl 5.28 and later, dies with an internal panic, or returns a wrong label.
The documented higher-level conversion functions in Net::IDN::Encode match each label against Unicode properties first, and that match itself dies on malformed input. Only a direct call to encode_punycode reaches the defect.
Root Cause
The root cause is missing input validation. The XS code assumed utf8_to_uvchr_buf would only be called on well-formed UTF-8 and did not check the returned length for the (STRLEN)-1 sentinel that signals a malformed sequence. The pure-Perl backend similarly assumed the UTF-8 flag implied well-formed bytes.
Attack Vector
An attacker supplies malformed UTF-8 bytes to any Perl application that forwards those bytes into a direct encode_punycode call. Typical exposure points include IDN normalization utilities, mail-address processors, and URL parsers that bypass the higher-level Net::IDN::Encode wrappers. No authentication or user interaction is required when the affected function is reachable from a network-facing service.
// Security patch in lib/Net/IDN/Punycode.xs
// Fix infinite loop on malformed UTF-8 input
for(in_p = skip_p = in_s; in_p < in_e;) {
c = utf8_to_uvchr_buf((U8*)in_p, (U8*)in_e, &u8);
+ if(u8 == (STRLEN)-1)
+ croak("malformed UTF-8 in input for encode_punycode");
c = NATIVE_TO_UNI(c);
if(c >= n && c < m) {
Source: GitHub commit 0918fb4
A follow-on patch adds an unconditional is_utf8_string check that rejects overlong encodings on every perl version:
// Security patch in lib/Net/IDN/Punycode.xs
// Reject overlong UTF-8 on every perl version
in_s = in_p = SvPVutf8(input, len);
in_e = in_s + len;
+ if(!is_utf8_string((U8*)in_s, len))
+ croak("malformed UTF-8 in input for encode_punycode");
+
length_guess = len;
if(length_guess < 64) length_guess = 64;
length_guess += 2;
Source: GitHub commit 572af0
Detection Methods for CVE-2026-87082
Indicators of Compromise
- Perl worker processes consuming 100% CPU with no forward progress while handling domain-name input.
- Process crashes logged as SIGBUS or panic originating from Net/IDN/Punycode.pm.
- Application logs showing Punycode output that does not round-trip back to the submitted domain string.
- Truncated UTF-8 byte sequences such as \\xE2\\x82 at label boundaries or stray \\xFF bytes in submitted domain data.
Detection Strategies
- Inventory Perl deployments and query installed distribution metadata to enumerate every host running Net::IDN::Encode below 2.590.
- Grep source repositories for direct calls to Net::IDN::Punycode::encode_punycode that bypass the safer Net::IDN::Encode wrappers.
- Add fuzz test cases covering truncated sequences (abc\\xE2\\x82), leading malformed bytes (\\xE2\\x82abc), stray bytes (abc\\xFF), and overlong encodings (a\\xC0\\x80b) as included in the upstream regression suite.
Monitoring Recommendations
- Alert on Perl processes that exceed a CPU-time threshold while holding a single request, which indicates the infinite-loop condition.
- Monitor for SIGBUS termination signals in application supervisors and container runtimes.
- Track error logs for the string malformed UTF-8 in input for encode_punycode, which the patched code emits via croak on rejected input.
How to Mitigate CVE-2026-87082
Immediate Actions Required
- Upgrade Net::IDN::Encode to version 2.590 or later on every host that ships a Perl interpreter.
- Audit application code for direct encode_punycode invocations and route them through Net::IDN::Encode::domain_to_ascii where feasible.
- Enforce request timeouts on Perl handlers that process domain names so a single request cannot pin a worker indefinitely.
Patch Information
The fix ships in Net-IDN-Encode-2.590-TRIAL. See the MetaCPAN changelog for release notes. The relevant commits are 0918fb4 (reject malformed sequences returned as (STRLEN)-1), 572af0 (reject overlong UTF-8 on every perl version), 59dc7f2 (validate UTF-8 regardless of caller warnings), and accb6df. Additional context is available on the Openwall OSS-Security thread.
Workarounds
- Call utf8::valid($input) and reject the request before invoking encode_punycode when the check fails.
- Replace direct encode_punycode calls with Net::IDN::Encode::domain_to_ascii, which pre-matches each label against Unicode properties and dies on malformed input.
- Wrap encoding calls in an eval block with an alarm-based timeout so an infinite loop is interrupted before it exhausts worker capacity.
# Upgrade Net::IDN::Encode to the patched release
cpanm Net::IDN::Encode@2.590
# Verify installed version on every Perl host
perl -MNet::IDN::Encode -E 'say $Net::IDN::Encode::VERSION'
# Reject malformed UTF-8 before encoding
perl -MNet::IDN::Punycode=encode_punycode -E '
my $label = shift;
die "malformed UTF-8" unless utf8::valid($label);
say encode_punycode($label);
' -- "$LABEL"
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

