Vulnerabilities

7 min readUpdated

CVE-2026-42533: the NGINX map heap overflow

Quick answer

CVE-2026-42533 is a heap buffer overflow in nginx's map module. When a map uses a regex and a string expression references the map's capture variables before the map output, or uses a self-dependent volatile map, the length and copy passes of nginx's script engine disagree and the worker writes past the allocation. It affects nginx 0.9.6 to 1.31.2 and is fixed in 1.31.3 and 1.30.4. A companion slice-module issue, CVE-2026-60005, was fixed in the same releases.

At a glance

critical severity
Identifier
CVE-2026-42533
Product
nginx (open source and NGINX Plus)
Affected
nginx open source 0.9.6 – 1.31.2; NGINX Plus releases built on those versions
Fixed in
nginx 1.31.3 (mainline); nginx 1.30.4 (stable); NGINX Plus R36 P7, PLS.37.0.3.1
CVSS
8.1 (CVSS 3.1) / 9.2 (CVSS 4.0), per F5; 7.0 per Red Hat
Disclosed
Known exploited (CISA KEV)
Not listed

Patched July 2026. Requires a non-default map/regex configuration. No in-the-wild exploitation reported; not in CISA KEV as of 24 October 2026.

01What is CVE-2026-42533?

CVE-2026-42533 is a heap buffer overflow in nginx's map module, and in the equivalent module in the stream subsystem. An unauthenticated attacker sends a crafted request, the worker process writes attacker-controlled bytes past a heap allocation, and the worker crashes and restarts. As with the related rewrite bug, the vendor describes code execution as possible where ASLR is disabled or bypassed; the dependable outcome is denial of service.

The nginx changelog credits Mufeed VH of Winfunc Research and Maxim Dounin, and the issue was disclosed on 15 July 2026. The affected code reaches back to nginx 0.9.6 (March 2011), when regex support was added to the map directive, so it spans fifteen years of releases.

Like the NGINX Rift rewrite overflow, this is a data-plane bug in nginx's script engine. The root cause is the same family of problem: the engine measures a buffer in one pass and fills it in another, and an attacker can make the two passes disagree.

02How does the map overflow happen?

nginx builds string values such as log lines, document roots and proxied headers using a two-pass script engine. The length pass totals the bytes needed and allocates exactly that; the copy pass writes the data. Both passes read the request's regex capture state, which is shared and mutable.

The bug appears when a single string expression references a positional capture such as $1 and then evaluates a regex-backed map. During the length pass, $1 may be empty, so it reserves little or no space. Evaluating the map then runs its own regex over attacker-controlled input and overwrites the shared capture array with a new, larger value. The copy pass revisits $1, now finds the new long capture, and copies it into the buffer that was sized for the old short one. The surplus overflows the allocation.

A second route reaches the same sink: a non-cacheable map marked volatile that depends on its own capture. Because its value can change between the length and copy passes, the two passes again disagree on size. Winfunc's write-up confirmed the overflow on a stream listener using ssl_preread, where the attacker-controlled TLS SNI hostname was copied into a one-byte allocation.

03Who is affected?

Open source nginx 0.9.6 through 1.31.2 is listed as vulnerable, along with NGINX Plus releases built on those versions. Exposure requires the specific configuration shape, so a version match alone does not mean you are exploitable.

The vulnerable shapes come straight from the upstream fix commit. The first is a string expression that reads a capture before a regex map; the second is a self-dependent volatile map.

The vulnerable patterns (from the upstream fix commit)
# A: capture read before the regex map output
map $uri $m {
    ~(?<capture>.*)  $capture;
}
set $capture "";
set $temp "$capture $m";   # $capture measured, then $m clobbers it

# B: self-dependent volatile map
map prefix:$capture $m_volatile {
    volatile;
    ~(?<capture>.*)  $capture;
}
set $capture "";
set $temp "$m_volatile";

04How do I audit my configuration?

Dump the merged configuration and look for two things: regex maps with captures, and volatile maps. Then confirm, by reading the surrounding blocks, whether a captured variable is used outside its own map block or before the map output in the same expression.

Finding risky map usage
nginx -T 2>/dev/null > /tmp/nginx-full.conf

# map blocks and regex entries that define a named capture
grep -nE '^\s*map\s|^\s*~\*?\S*\(' /tmp/nginx-full.conf

# volatile maps (the self-dependent variant)
grep -nE '^\s*volatile\s*;' /tmp/nginx-full.conf

# for each captured name, see where it is used outside its map
for c in $(grep -E '^\s*~' /tmp/nginx-full.conf \
           | grep -oE '\?<[A-Za-z_][A-Za-z0-9_]*>' | tr -d '?<>' | sort -u); do
  echo "== \$$c"; grep -nE "\\$\{?$c\b" /tmp/nginx-full.conf
done

05How is it fixed?

Upgrade to nginx 1.31.3 (mainline) or 1.30.4 (stable); NGINX Plus users should move to R36 P7 or PLS.37.0.3.1 (LTS), both released on 15 July 2026. The fix records the end of the allocated buffer and routes every literal, variable and capture copy through a shared length guard. If a copy would exceed the buffer, nginx now logs "no buffer space in script copy", aborts the script and returns an internal error instead of writing out of bounds — it fails closed.

Distribution packages carry it too: Debian shipped it in nginx 1.26.3-3+deb13u8 for trixie (DSA-6496-1) and in 1.22.1-9+deb12u10 for bookworm through Debian LTS (DLA-4784-1). Match the package version your distribution publishes.

If you cannot upgrade at once, remove the trigger. Do not use unnamed captures in these expressions; use a uniquely named capture and reference it only inside the same block as the regex match. Reorder expressions so a map output is not preceded by a capture reference it depends on.

  • Primary fix: upgrade to nginx 1.31.3 / 1.30.4, or the matching distro package
  • Config mitigation: name captures and use them only inside their own map block
  • Avoid self-referential volatile maps built from their own capture
  • Restart nginx so workers reload the patched binary

07What can an edge proxy actually do here?

The honest answer mirrors the rewrite bug. CVE-2026-42533 executes inside the nginx worker that processes the request, so a filter inside that same vulnerable nginx cannot be relied on to stop it. The stream variant is worse for edge filtering, because it is driven by the TLS SNI during the handshake — before any HTTP-layer inspection runs. Understanding where TLS sits helps here: see what SSL/TLS is.

A separate, patched tier in front of an origin reduces exposure and absorbs the crash-loop denial of service, in the same way any reverse proxy shields an origin. It cannot make an unpatched nginx safe, which is the general limit of any virtual patch. Patch first; use edge protection to limit blast radius and to soak up flooding. For what that layer does more broadly, see what a WAF is.

Questions

Frequently asked questions

No. The map must use a regex capture, and a string expression must reference that capture before the map's output, or the map must be a self-dependent volatile map. A map used in the ordinary way, where the captured variable stays inside its own block, is not exploitable. Audit the configuration rather than assuming from the version alone.

nginx 1.31.3 (mainline) and 1.30.4 (stable), plus NGINX Plus R36 P7 and PLS.37.0.3.1. Distribution builds ship it under their own numbers, for example Debian trixie 1.26.3-3+deb13u8. The patch adds a buffer-end bounds check so an oversized copy is aborted and logged as 'no buffer space in script copy' instead of overflowing.

It was fixed in the same July 2026 releases. CVE-2026-60005 is an uninitialised-memory read in the slice module, triggered by unnamed regex captures with the slice directive or by a background cache update. It can disclose worker memory or restart the worker. The slice module is not built by default, so fewer deployments are exposed.

Not reliably, if the vulnerable nginx is the server handling the request. The overflow happens inside that worker, and the stream variant fires on the TLS SNI during the handshake before HTTP inspection. A separate patched proxy in front reduces exposure and absorbs the crash-loop denial of service, but patching the affected nginx is the real fix.

The reliable result is a worker crash, which is a denial of service. F5 states that code execution is possible where ASLR is disabled or bypassed. Red Hat rates it Important with a CVSS 3.1 score of 7.0, noting that ASLR, enabled by default on its systems, significantly reduces the code-execution risk. ASLR raises the bar but is not a fix, so patch anyway.

Sources

Sources and verification

Both map patterns from the fix commit loaded into nginx 1.22.1 with nginx -t, and the audit greps and loop run with GNU grep 3.8 against a test configuration, on Debian 12, October 2026.

  1. 01NVD — CVE-2026-42533 · NVD
  2. 02nginx security advisories · nginx.org
  3. 03F5 advisory K000162097 · F5
  4. 04Winfunc Research — CVE-2026-42533 disclosure record · Winfunc Research
  5. 05nginx fix commit b767540 (script buffer overrun protection) · nginx GitHub
  6. 06F5 advisory K000162100 (CVE-2026-60005, slice module) · F5
  7. 07Debian security tracker — CVE-2026-42533 · Debian
  8. 08Red Hat — CVE-2026-42533 · Red Hat
  9. 09NGINX Plus release notes · F5 NGINX docs
  10. 10nginx changelog (CHANGES) · nginx.org

Last updated