Skip to main content
Vulnerability Database/CVE-2026-87082

CVE-2026-87082: Net::IDN::Punycode Perl DOS Vulnerability

CVE-2026-87082 is a denial of service flaw in Net::IDN::Punycode for Perl that causes hangs, crashes, or incorrect labels through malformed UTF-8 input. This post explains its impact, affected versions, and mitigation steps.

Published:

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.

text
// 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:

text
// 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.
bash
# 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.

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.