> ## Documentation Index
> Fetch the complete documentation index at: https://blog.onetsolutions.net/llms.txt
> Use this file to discover all available pages before exploring further.

# nginx (CVE-2026-42533): Two Heap Overflows, and Why Patching the First Did Not Fix the Second

> A buffer overflow in nginx's map-and-regex handling affects fifteen years of releases. If you patched for Nginx Rift in May, you are still exposed.

*Published on August 12, 2026*

<Warning>
  **CVE-2026-42533 — buffer overflow when using `map` and regex.** Affects nginx **0.9.6 through 1.31.2**. Fixed in **1.30.4** (stable) and **1.31.3** (mainline). If you patched in May for Nginx Rift, that fix does **not** cover this one.
</Warning>

## The part most people got wrong

Two heap overflows landed in nginx's script engine within a few months, and they look similar enough that they get confused. They are not the same bug, and — this is the part that matters — **the version that fixed one still runs the other**.

|                | Nginx Rift                | This one             |
| -------------- | ------------------------- | -------------------- |
| CVE            | CVE-2026-42945            | **CVE-2026-42533**   |
| Component      | `ngx_http_rewrite_module` | `map` + regex        |
| Affected       | 0.6.27 → 1.30.0           | **0.9.6 → 1.31.2**   |
| Fixed in       | 1.30.1+, 1.31.0+          | **1.30.4+, 1.31.3+** |
| nginx severity | medium                    | **major**            |

Read the last two rows together. Rift was fixed in 1.30.1. CVE-2026-42533 affects everything up to 1.31.2. A server updated to 1.30.1 in May, ticked off as "patched", is squarely in range.

If your last nginx update was prompted by the Rift coverage, you are not done.

## The flaw

Both bugs come from the same design. nginx evaluates script expressions in two passes: the first measures how much buffer it needs, the second writes into it. When the state the engine relies on changes between the two passes, the write outruns the size that was measured, and the overflow lands on the heap.

Rift got there through a stale flag. This one gets there through PCRE capture state: there is no save-and-restore around it, so captures from one evaluation clobber another.

Triggering it needs a specific shape of configuration — a regex-based `map` block, and a directive that references both a regex capture and the map's output variable in the same expression. That is not exotic. It is a normal way to write a routing rule.

<Info>
  Note the severity gap. nginx rates this **major** and rates Rift **medium**, while several third-party trackers scored Rift at CVSS 9.2. Vendor and third-party scores are measuring different things; the version ranges above are the part to act on, not the number.
</Info>

## Sizing your exposure

| Profile                                                     | Exposure                | Action                                                           |
| ----------------------------------------------------------- | ----------------------- | ---------------------------------------------------------------- |
| nginx 1.30.4+ or 1.31.3+                                    | None                    | Nothing to do                                                    |
| nginx between 1.30.1 and 1.31.2, "already patched for Rift" | **Critical**            | Update now — this is the trap                                    |
| nginx below 1.30.1, no `map` with regex anywhere            | Moderate                | Both bugs apply; update at the next window                       |
| Container images with a pinned nginx tag                    | **Often forgotten**     | The published exploit chain was calibrated against Docker images |
| Shared hosting where you do not manage nginx                | Handled by the provider | Nothing to do on your side                                       |

That fourth row deserves emphasis. A pinned `nginx:1.30.1` in a Dockerfile does not update itself, and rebuilding is the only way it changes. The public full-chain proof of concept was tuned specifically for Docker deployments — base image, package snapshot and source revision.

## Checking and updating

Find out what you are actually running, which is not always what your package manager thinks:

```bash theme={null}
# The binary's own version
nginx -v

# Every nginx process on the box, in case an old one is still resident
ps -eo pid,etime,cmd | grep "[n]ginx: master"
```

Debian, Ubuntu and derivatives:

```bash theme={null}
sudo apt update && sudo apt install --only-upgrade nginx
sudo systemctl restart nginx
nginx -v
```

AlmaLinux, Rocky Linux and RHEL:

```bash theme={null}
sudo dnf upgrade nginx
sudo systemctl restart nginx
nginx -v
```

<Warning>
  A reload is not enough here. `nginx -s reload` starts new workers but the master process keeps running the old binary. Use `restart` so the whole process tree picks up the patched code, then confirm with `nginx -v`.
</Warning>

For containers, rebuild rather than patch in place:

```bash theme={null}
# Pull the rebuilt base image and recreate the container
docker compose pull
docker compose up -d

# Confirm what the running container actually has
docker compose exec web nginx -v
```

## If you cannot update immediately

There is no configuration flag that disables the bug. What you can do is remove the trigger: if a `map` block built on a regex feeds a variable that is used alongside a regex capture in the same directive, rewriting that expression closes the path until you patch.

Find the candidates:

```bash theme={null}
# map blocks whose source is a regex
grep -rn "^\s*map\s" /etc/nginx/ -A 3 | grep -E "~\*?\s"

# directives combining a capture ($1..$9) with another variable
grep -rnE '\$[1-9].*\$[a-z_]+|\$[a-z_]+.*\$[1-9]' /etc/nginx/
```

Treat this as a stopgap measured in days, not a fix.

## The wider lesson

Two bugs of the same class, in the same engine, months apart, with overlapping-but-different version ranges. The failure mode is not "we did not patch" — it is "we patched, and assumed that settled it".

When an advisory names a version, the useful question is not *did we update?* but *did we update past the range in this advisory?* They are different questions, and only the second one has an answer you can check.

Our [guide to auditing and hardening nginx on a VPS](/en/audit-and-harden-nginx-on-a-vps) covers the routine that catches this class of thing before an advisory forces it.

Questions about a server hosted with us? [Our team is available](https://help.onetsolutions.net/console/support) from your client area.
