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

CVE-2026-87078: Perl Net::IDN::Punycode Memory Leak Vulnerability

CVE-2026-87078 is a memory leak flaw in Perl Net::IDN::Punycode affecting versions 2.302 through 2.589. Attackers can exhaust memory by sending invalid labels. This article covers technical details, impact, and mitigation.

Published:

CVE-2026-87078 Overview

CVE-2026-87078 is a memory leak vulnerability in the Net::IDN::Punycode Perl module, affecting versions from 2.302 before 2.590. The flaw resides in the XS backend of decode_punycode, which allocates an output scalar sized at twice the input length before validating the input. Because the scalar is only released on the success path, each rejected label leaks its allocated buffer. An unauthenticated remote sender can grow the target process by twice the label length per rejected call, without needing a single successful decode. The vulnerability is tracked under CWE-401: Missing Release of Memory after Effective Lifetime.

Critical Impact

Remote, unauthenticated attackers can exhaust process memory by repeatedly submitting invalid Punycode labels, leading to denial of service in Perl applications performing internationalized domain name (IDN) decoding.

Affected Products

  • Net::IDN::Punycode for Perl, versions 2.302 through versions before 2.590
  • Only the XS backend is affected; the pure-Perl backend is not impacted
  • Applications that call decode_punycode on attacker-controlled input (mail servers, DNS tooling, URL parsers, web frameworks handling IDN)

Discovery Timeline

Technical Details for CVE-2026-87078

Vulnerability Analysis

The XS backend of Net::IDN::Punycode implements decode_punycode in C for performance. The routine allocates a Perl scalar (SV) to hold the decoded Unicode output before performing input validation. The buffer is sized at twice the input label length to accommodate the widest possible UTF-8 expansion.

The function contains three croak sites that reject malformed labels. Each of these error paths raises a Perl exception without first calling SvREFCNT_dec on the pre-allocated scalar. The scalar is only freed on the successful return path, so every rejected call leaves an orphaned buffer in the interpreter's memory pool.

Compounding the leak, no length bound is applied to labels in the to-Unicode direction. The 63-byte DNS label limit is only enforced during ASCII encoding, so an attacker can submit arbitrarily large invalid labels to maximize the leak per request.

Root Cause

The root cause is a missing cleanup step in an error-handling path, classified as [CWE-401]. The XS code pattern allocates first and validates second, then transfers ownership to the caller only on success. Because croak performs a longjmp out of the function, ordinary local cleanup is skipped, and the pre-allocated scalar becomes unreachable.

Attack Vector

Any Perl service that decodes attacker-supplied Punycode labels is exposed. Mail transfer agents processing IDN addresses, HTTP servers normalizing hostnames, and DNS-aware tooling all present remote attack surface. The attacker submits a stream of invalid Punycode labels; each rejection allocates roughly 2 * label_length bytes that are never freed until the process terminates.

text
// Patch 1: Introduce croak_free helper to release the scalar before croaking
// Source: https://github.com/robrwo/Net-IDN-Encode/commit/92572f726e48af5559de4cc8a831463b79dfb217.patch
  *end = *start + SvLEN(sv);
 }

+static void
+croak_free(SV *sv, const char *msg)
+{
+  SvREFCNT_dec(sv);
+  croak("%s", msg);
+}
+
 MODULE = Net::IDN::Punycode PACKAGE = Net::IDN::Punycode

 SV*
text
// Patch 2: Mortalise RETVAL so croaks cannot leak it; croak_free helper removed
// Source: https://github.com/robrwo/Net-IDN-Encode/commit/edad63e0eeeeb18d93bc6dfe4d9dcdff9c244e1b.patch
  *end = *start + SvLEN(sv);
 }

-static void
-croak_free(SV *sv, const char *msg)
-{
-  SvREFCNT_dec(sv);
-  croak("%s", msg);
-}
-
 MODULE = Net::IDN::Punycode PACKAGE = Net::IDN::Punycode

 SV*

Detection Methods for CVE-2026-87078

Indicators of Compromise

  • Sustained, monotonic growth of resident set size (RSS) in Perl processes that handle IDN input, without a corresponding increase in workload
  • Elevated rate of Punycode decode exceptions in application logs, particularly invalid input, overflow, or similar croak messages from Net::IDN::Punycode
  • Bursts of inbound traffic containing malformed xn-- labels from a small set of source addresses

Detection Strategies

  • Inventory Perl applications and enumerate installed versions of Net::IDN::Encode and Net::IDN::Punycode; flag any XS-backed install between 2.302 and 2.590
  • Instrument long-running Perl services with per-process memory watchdogs and alert on unbounded growth trends
  • Correlate application-layer parse errors on IDN input with process memory metrics to distinguish benign malformed input from active abuse

Monitoring Recommendations

  • Track RSS, VSZ, and Perl arena allocation counters for services that call decode_punycode
  • Log source IP, label length, and rejection reason for every failed Punycode decode to enable rate-based alerting
  • Apply rate limiting on IDN-heavy endpoints and alert when a single client generates a high ratio of decode failures to successes

How to Mitigate CVE-2026-87078

Immediate Actions Required

  • Upgrade Net::IDN::Encode to version 2.590 or later, which ships the fixed XS backend
  • Where an upgrade is not immediately possible, switch callers to the pure-Perl backend, which is not affected
  • Restart long-running Perl workers after upgrade to release any previously leaked memory
  • Apply process-level memory limits (ulimit -v, systemd MemoryMax, container limits) so a partial exposure cannot exhaust host memory

Patch Information

The issue is fixed in Net-IDN-Encode-2.590-TRIAL and later. Two upstream commits address the flaw: commit 92572f7 introduces a croak_free helper that releases the output scalar before raising the exception, and commit edad63e supersedes that helper by mortalising RETVAL so all croak sites are covered without per-call cleanup. Release notes are published on MetaCPAN.

Workarounds

  • Force applications to use the pure-Perl backend by setting the appropriate backend selector before loading Net::IDN::Punycode
  • Reject labels longer than 63 bytes at the application layer before invoking decode_punycode, mirroring the DNS limit that the vulnerable code omits
  • Deploy an upstream proxy or WAF rule that filters or rate-limits requests containing malformed xn-- prefixes
  • Configure automatic worker recycling after a bounded number of requests or memory threshold to cap the impact of any residual leak
bash
# Verify installed version and upgrade via cpanm
perl -MNet::IDN::Encode -E 'say $Net::IDN::Encode::VERSION'
cpanm Net::IDN::Encode@2.590

# Enforce a process memory ceiling for Perl workers (systemd unit example)
# [Service]
# MemoryMax=512M
# Restart=on-failure

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.