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

CVE-2026-13221: Perl Regex Overflow Vulnerability

CVE-2026-13221 is a regex overflow flaw in Perl through version 5.43.9 that causes incorrect pattern matches with large alternations. This article covers the technical details, affected versions, impact, and mitigation.

Published:

CVE-2026-13221 Overview

CVE-2026-13221 affects Perl versions through 5.43.9. The vulnerability lives in Perl_study_chunk, the routine that compiles alternations of fixed-string branches into a trie structure. When the alternation contains more than 65,535 branches, a 16-bit field that stores the delta between the first branch and the shared tail overflows. The trie's match decision table is silently truncated with no warning or error.

The result is a regular expression that returns both false positives and false negatives. When such a pattern gates an access control or input filtering decision, the outcome is wrong. The flaw is tracked as an integer overflow weakness [CWE-190].

Critical Impact

Silent incorrect regex matching in Perl can bypass allow-lists, deny-lists, and authorization filters in any downstream application relying on affected patterns.

Affected Products

  • Perl interpreter versions through 5.43.9
  • Applications and web frameworks embedding vulnerable Perl builds
  • CPAN modules that dynamically build large alternation patterns from data

Discovery Timeline

  • 2026-07-13 - CVE-2026-13221 published to NVD
  • 2026-07-13 - Public discussion on the Openwall OSS Security list
  • 2026-07-14 - Last updated in NVD database

Technical Details for CVE-2026-13221

Vulnerability Analysis

Perl compiles alternations of literal strings, for example foo|bar|baz, into a trie for efficient matching. The trie construction logic in regcomp_study.c records the offset between the starting branch (startbranch) and the shared tail node in a 16-bit field. When the branch count grows past 65,535, the offset exceeds U16_MAX and wraps.

A wrapped offset causes the trie's decision table to be truncated. The compiled regex still runs, but it consults an incomplete state machine. Some inputs match when they should not, and other inputs fail to match when they should. There is no exception, no warning, and no log entry to signal the corrupted compilation.

The integrity impact is high because the match result is wrong in both directions. Any code that uses regex results for security decisions inherits the flaw.

Root Cause

The root cause is an undersized integer field in the trie compiler. The offset between startbranch and tail must fit in 16 bits, but the branch-count guard for entering trie construction did not enforce this constraint. Large alternations, which can arise from generated code or user-supplied word lists, cross the threshold and overflow.

Attack Vector

Exploitation requires an application to compile a Perl regex whose alternation contains more than 65,535 fixed-string branches. Applications that build patterns from external data, such as domain block-lists, keyword filters, or dynamically merged rule sets, are the most exposed. An attacker who controls or influences the list contents can shape the trie so that specific attacker-chosen strings fall into the truncated section.

c
                            tail = regnext( tail );
                        }

+                        /* The code below currently saves the difference from
+                         * start to finish in a 16-bit field, causing
+                         * GH #23388.  This defeats the design of batching
+                         * tries into chunks that each fit.  khw thinks it is
+                         * too late in the 5.44 cycle to relook at the design,
+                         * so for now anyway, don't make a trie that would
+                         * overflow */
+                        if (tail - startbranch >= U16_MAX) {
+                            continue;
+                        }

                        DEBUG_TRIE_COMPILE_r({
                            regprop(RExC_rx, RExC_mysv, tail, NULL, pRExC_state);

Source: Perl5 commit 03f74bbb. The patch adds an early continue that skips trie construction when the branch-to-tail distance would overflow U16_MAX, preserving correctness at the cost of falling back to slower branch matching.

Detection Methods for CVE-2026-13221

Indicators of Compromise

  • Regex expressions in application code or configuration containing more than 65,535 pipe-separated fixed branches
  • Security filters, allow-lists, or deny-lists whose match results diverge from equivalent string comparisons
  • Perl processes running versions at or below 5.43.9 that compile dynamically generated alternation patterns

Detection Strategies

  • Inventory Perl interpreter versions across servers, containers, and CI runners and flag any build at or below 5.43.9
  • Grep source and generated code for regex constructions that concatenate large lists into a single alternation using join "|", ...
  • Add unit tests that compare regex-based filter decisions against a canonical string set membership check

Monitoring Recommendations

  • Log the length and branch count of dynamically compiled regex patterns to identify oversized alternations at runtime
  • Monitor authorization and content-filter decisions for anomalies such as unexpected allows on previously blocked strings
  • Track deployment of Perl package updates through configuration management and alert on hosts that lag behind

How to Mitigate CVE-2026-13221

Immediate Actions Required

  • Apply the upstream patch from Perl5 commit 03f74bbb or upgrade to a Perl release that incorporates the fix
  • Audit every regex used for security decisions and refactor patterns that exceed 65,535 branches into smaller alternations or hash-based lookups
  • Rebuild and redeploy any downstream distributions and container images that embed vulnerable Perl binaries

Patch Information

The fix in regcomp_study.c prevents trie construction when the distance from startbranch to tail would meet or exceed U16_MAX. The regex still compiles, but Perl falls back to non-trie matching for that alternation, preserving correctness. A regression test was added under t/re/pat_advanced.t (GH #23388) that compiles a "aaa".."mzz" and "naa".."zzz" alternation to exercise the overflow condition. Track further discussion on the Perl5 issue tracker.

Workarounds

  • Split oversized alternations into multiple smaller regex objects and test each independently
  • Replace large fixed-string alternations with a hash lookup, trie library, or Aho-Corasick implementation outside the regex engine
  • Restrict inputs that drive dynamic pattern generation so untrusted data cannot inflate branch counts past 65,535
bash
# Verify the installed Perl version before and after patching
perl -e 'print $^V, "\n"'

# Quick sanity check that a suspect alternation still matches correctly
perl -e '
  my $x = join "|", "aaa".."mzz";
  my $y = join "|", "naa".."zzz";
  print "fnord" =~ m/(?:$x)|(?:$y)/ ? "MATCH\n" : "NO MATCH\n";
'

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

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.