An nginx location that serves files with alias, changes the URI with rewrite and then reads $request_filename can overflow the worker’s heap. That is CVE-2026-15176, and the same overflow is reachable when $request_filename only appears in a log_format. Every upstream release from 0.1.29 through 1.31.6 carries the bug, so the question for you is not whether your nginx build is affected but whether your config has that shape and whether your distro’s backport is installed yet.
Below are the fixed package versions for Ubuntu, Debian and Amazon Linux 2023, an nginx -T audit for the risky directives, the upgrade on each distro, and a config rewrite for hosts that cannot patch yet. CVE-2026-93479, the related map regex overflow, is fixed in the same builds. All of it was run in October 2026 on an Ubuntu 26.04 LTS lab VM, with Ubuntu 24.04, Ubuntu 22.04, Debian 13 and Amazon Linux 2023 checked in containers on that VM, and no step disables a security control to make the patch go through.
Fixed nginx versions for CVE-2026-15176
Compare the installed package version, not the nginx -v string, because Ubuntu and Debian backport the fix onto the old upstream base. Ubuntu shipped the fixes in USN-8955-1 on 26 October 2026, Debian in DSA-6575-1, and Amazon in ALAS2023-2026-3263. The rows marked “lab” were installed and upgraded on our test machine:
| Distro | Release | Fixed nginx package | CVE-2026-93479 in the same build | Checked |
|---|---|---|---|---|
| Ubuntu | 26.10 | 1.30.4-7ubuntu1.1 | Yes | Tracker only |
| Ubuntu | 26.04 LTS | 1.28.3-2ubuntu1.12 | Yes | Lab |
| Ubuntu | 24.04 LTS | 1.24.0-2ubuntu7.19 | Yes | Lab |
| Ubuntu | 22.04 LTS | 1.18.0-6ubuntu14.22 | Yes | Lab |
| Ubuntu | 20.04 and older | Needs triage, no fix | No fix | Tracker only |
| Debian | 13 trixie | 1.26.3-3+deb13u10 | Yes | Lab |
| Debian | 14 forky / sid | 1.30.4-8 and later | Yes | Tracker only |
| Debian | 12 bookworm | Vulnerable, no fix yet | No fix | Tracker only |
| Amazon Linux | 2023 | nginx-1.30.6-1.amzn2023.0.1 | Yes | Lab |
| nginx.org | stable / mainline | 1.30.6 / 1.31.7 | Yes | Advisory |
| RHEL 8, 9, 10 | all | No fix yet (“a fix is being pursued”) | RHEL 8 not affected; 9 and 10 base package fix deferred | Advisory |
If you run Debian 12 or a RHEL rebuild, skip ahead to the config rewrite near the end, because that is the only control you have until those packages ship. Our combined check-and-patch guide for both nginx CVEs also tracks those two families and the three other bugs the same releases fixed.
The config shape behind the overflow
CVE-2026-15176 is not reachable on a default install. The bug sits in the code that maps a rewritten URI back to a file path under alias, so the vulnerable path only runs when your config combines those pieces. F5’s CVE record describes two shapes, and your host is exposed if either one holds:
- A
locationusesalias, arewritechanges the URI inside it, and asetorreturnreferences$request_filename. - A
log_formatused by anaccess_logreferences$request_filename.
The second shape is the one people miss, since a log format looks harmless and often lives in nginx.conf far from the server blocks. CVE-2026-93479 is a sibling bug in nginx’s string expression code: a map with regex matching whose capture variables are read by root or a log format before the map’s own output variable, or, under certain conditions, a non-cacheable variable used in a string expression. Upstream says it affects 1.30.0 to 1.30.5 and 1.31.2 to 1.31.6. Red Hat describes it as a regression from the fix for CVE-2026-42533, which is why older Ubuntu and Debian bases that carry that backport are affected too.
Both records carry CVSS 4.0 9.2 and CVSS 3.1 8.1 with high attack complexity. The realistic outcome is a worker crash and restart, which turns into a denial of service under repeated requests. Code execution is only on the table when ASLR is disabled or the attacker can bypass it. EPSS scored 15176 at 0.008 and 93479 at 0.012 on 28 October, CISA’s SSVC entry on both records says exploitation “none”, and we found no public proof of concept. Red Hat rates CVE-2026-15176 Important. None of that makes it safe to wait on an internet-facing host with the vulnerable shape, but it does make the config audit the right first step.
Do not mix this up with CVE-2026-42945, the “NGINX Rift” bug from May 2026. Rift is a different heap overflow in the rewrite module, triggered by unnamed PCRE captures in a rewrite replacement containing ?, and it was fixed back in 1.30.1 and 1.31.0. A host patched for Rift is still vulnerable to CVE-2026-15176.
An nginx -T audit for alias and $request_filename
Grep the files under /etc/nginx and you miss anything pulled in from another path, so audit the merged config that nginx actually loads. nginx -T prints every included file with a # configuration file header, and awk can carry that header along so each hit names its file. The first command finds every use of $request_filename:
sudo nginx -T 2>/dev/null | awk '/^# configuration file /{f=$4} /\$request_filename/{print f" "$0}'
The second lists every alias and rewrite line so you can see which locations combine them:
sudo nginx -T 2>/dev/null | awk '/^# configuration file /{f=$4} /^[[:space:]]*(alias|rewrite)[[:space:]]/{print f" "$0}'
On the lab VM we loaded a deliberately risky download vhost on port 8080 before running the audit. Both commands flagged it, and all four lines point at the same file:
/etc/nginx/conf.d/files.conf: log_format filelog '$remote_addr "$request" $status file=$request_filename';
/etc/nginx/conf.d/files.conf: set $served $request_filename;
/etc/nginx/conf.d/files.conf: alias /srv/files/;
/etc/nginx/conf.d/files.conf: rewrite ^/dl/v1/(.*)$ /dl/$1 break;
That file matches both documented shapes at once: an alias location with a rewrite and a set on $request_filename, plus a log format that writes the same variable. Empty output from the first command means the log format path is closed. If the second command prints alias and rewrite lines from the same file, open that file and check whether they sit in the same location block, because awk does not track braces. A clean result on both commands means the vulnerable code path is not reachable through your current config, and the patch becomes routine maintenance rather than an emergency. For CVE-2026-93479, look for map blocks with ~ regex keys whose captures are used outside the map; that catches the map shape but not the non-cacheable variable path, so the package upgrade is the real fix there.
Package versions on Ubuntu and Debian
The version check takes seconds. On Ubuntu 26.04, 24.04 and Debian 13 the binary ships in the nginx package, so query it with nginx-common:
dpkg-query -W -f='${Package} ${Version}\n' nginx nginx-common && nginx -v
Before the upgrade, the Ubuntu 26.04 lab VM still had the release-day build, while nginx -v reported only the upstream base:
nginx 1.28.3-2ubuntu1
nginx-common 1.28.3-2ubuntu1
nginx version: nginx/1.28.3 (Ubuntu)
Here 1.28.3-2ubuntu1 is older than the fixed 1.28.3-2ubuntu1.12, so this host is vulnerable. The upstream string stays at 1.28.3 after patching too, which is why nginx -v alone tells you nothing on Ubuntu or Debian. On Ubuntu with the pro client, sudo pro fix CVE-2026-15176 --dry-run gives the same answer from Canonical’s own data and prints the exact upgrade it would run.
Which package carries the binary depends on the release, and the lab installs showed three layouts:
- Ubuntu 26.04, Ubuntu 24.04 and Debian 13 ship the binary in
nginx, next tonginx-common. - Ubuntu 22.04 ships it in
nginx-core, with each dynamic module as its ownlibnginx-mod-*package at the same version. - Amazon Linux 2023 ships it in
nginx-core, upgraded together withnginxandnginx-filesystem.
Naming every installed package in the upgrade is the safe way to make sure no module stays at the old version on 22.04, so list everything nginx-related that is actually installed:
dpkg-query -W -f='${Package} ${Status}\n' '*nginx*' | awk '/ installed$/{print $1}'
That list feeds straight into the upgrade below. It works on every Ubuntu and Debian release, so use it everywhere if you manage a mixed fleet.
The apt upgrade that closes both CVEs
Refresh the package index first, because a host that has not run apt update since 26 October will not see the fixed build:
sudo apt-get update
Then upgrade only the installed nginx packages. --only-upgrade stops apt from pulling in a package you never had:
sudo apt-get install --only-upgrade -y $(dpkg-query -W -f='${Package} ${Status}\n' '*nginx*' | awk '/ installed$/{print $1}')
On the Ubuntu 26.04 VM the transaction replaced two packages:
The following packages will be upgraded:
nginx nginx-common
2 upgraded, 0 newly installed, 0 to remove and 2 not upgraded.
Unpacking nginx (1.28.3-2ubuntu1.12) over (1.28.3-2ubuntu1) ...
Unpacking nginx-common (1.28.3-2ubuntu1.12) over (1.28.3-2ubuntu1) ...
Setting up nginx-common (1.28.3-2ubuntu1.12) ...
Setting up nginx (1.28.3-2ubuntu1.12) ...
The package scripts restarted nginx on their own: systemctl show nginx -p ActiveEnterTimestamp read 01:37:46, the minute of the upgrade, and ps showed a new master process PID running the new binary. That restart matters, because a reload alone keeps the old binary in memory. On 22.04 the same command moved nine packages from 1.18.0-6ubuntu14 to 1.18.0-6ubuntu14.22, including all six module packages, and on 24.04 and Debian 13 it landed 1.24.0-2ubuntu7.19 and 1.26.3-3+deb13u10. The changelog is the proof that the fix is the backport and not just a version bump:
zgrep -n -E 'CVE-2026-(15176|93479)' /usr/share/doc/nginx/changelog.Debian.gz
Ubuntu’s patch names describe exactly what changed, with 15176 fixed in the alias mapping and 93479 in the script engine:
4: - debian/patches/CVE-2026-15176.patch: Avoid post-rewrite URI to path
6: - CVE-2026-15176
8: - debian/patches/CVE-2026-93479.patch: Script: reserved memory overrun
11: - CVE-2026-93479
Debian 13’s changelog uses its own wording (“reject URI to path mapping with alias”), and on Ubuntu 22.04 read the file under /usr/share/doc/nginx-core/ instead. The screenshot below shows the full post-patch check on the 26.04 VM, ending with pro fix marking the CVE resolved:

If you are planning the release jump at the same time, the Ubuntu 26.04 to 26.10 upgrade lands 26.10’s fixed build, but patch first so the host is not exposed while you schedule it.
Amazon Linux 2023 and the release version lock
Amazon Linux 2023 pins each instance to the repository snapshot it booted from, so a plain dnf upgrade can report nothing to do while ALAS2023-2026-3263 is sitting in a newer snapshot. Our container image was release 2023.12.20261021, three days older than the advisory, and it installed nginx-1.30.5-1.amzn2023.0.1, which sits inside both CVE ranges. A default dnf check-update nginx on it returned nothing. Ask for the latest release explicitly:
dnf updateinfo list --releasever=latest --security | grep -i nginx
With --releasever=latest the advisory appears against all three nginx packages:
ALAS2023-2026-3263 Medium/Sec. nginx-1:1.30.6-1.amzn2023.0.1.x86_64
ALAS2023-2026-3263 Medium/Sec. nginx-core-1:1.30.6-1.amzn2023.0.1.x86_64
ALAS2023-2026-3263 Medium/Sec. nginx-filesystem-1:1.30.6-1.amzn2023.0.1.noarch
Amazon rates the advisory Medium, the same as nginx.org, while F5’s CVSS scores read higher. dnf updateinfo info ALAS2023-2026-3263 --releasever=latest lists all five CVEs it covers, 15176 and 93479 included. Upgrade the nginx packages from the latest release:
sudo dnf upgrade -y --releasever=latest 'nginx*'
Unlike the Debian family, Amazon rebased to upstream 1.30.6 instead of backporting, so here nginx -v does change. Confirm the packages and the binary:
rpm -q nginx nginx-core && nginx -v
Both packages and the binary report 1.30.6:
nginx-1.30.6-1.amzn2023.0.1.x86_64
nginx-core-1.30.6-1.amzn2023.0.1.x86_64
nginx version: nginx/1.30.6
The container had no systemd, so no restart was captured there. On an EC2 instance, run sudo systemctl restart nginx after the upgrade and check that the master process start time moved. If you want the whole instance on the new snapshot rather than just nginx, sudo dnf upgrade --releasever=latest moves everything. The same lock catches people on local test boxes, such as an Amazon Linux 2023 VM on KVM built from an older qcow2 image.
Patched builds return 500 on alias after rewrite
This is the part that will page someone after the upgrade. The fix does not quietly make the risky pattern safe: Ubuntu’s patch is titled “Avoid post-rewrite URI to path mapping with alias”, and the patched build refuses that mapping outright. With the risky vhost still loaded, a request for /dl/v1/readme.txt, which the rewrite turns into /dl/readme.txt, came back as HTTP 500 on the patched 26.04 VM (1.28.3-2ubuntu1.12), while /dl/readme.txt without the rewrite still returned 200. The error log names the cause:
sudo tail -2 /var/log/nginx/error.log
Each refused request logs an [alert] line, followed by a second one while logging the request:
2026/10/29 01:49:36 [alert] 3348#3348: *6 "alias" cannot be used in location "/dl/" where URI was rewritten, client: 127.0.0.1, server: files.example.com, request: "GET /dl/v1/readme.txt HTTP/1.1", host: "files.example.com"
2026/10/29 01:49:36 [alert] 3348#3348: *6 "alias" cannot be used in location "/dl/" where URI was rewritten while logging request, client: 127.0.0.1, server: files.example.com, request: "GET /dl/v1/readme.txt HTTP/1.1", host: "files.example.com"
nginx -t still passed on that config, so a syntax check before the upgrade will not warn you. If the audit above flagged an alias location with a rewrite, expect those rewritten URLs to fail after patching and fix the config in the same change window. Watch for the 500s with a quick grep after the upgrade:
sudo grep -c 'cannot be used in location' /var/log/nginx/error.log
Each refused request writes two alert lines, so the lab VM read 4 after two refused requests. Any count above zero is a location you still need to rewrite. Feed the same string into your log alerting if you already monitor nginx with Prometheus and Grafana, since a rising 5xx rate on one path is how this shows up on a dashboard.
A config without alias or $request_filename
F5’s workaround is short: avoid alias in a location and avoid $request_filename. That rewrite is the only protection on Debian 12 and RHEL until their packages ship, and it is also what keeps a patched host from serving 500s. Switching the location to root keeps the rewrite working, because root appends the full URI instead of replacing the location prefix. The files move to match, so /srv/files/readme.txt becomes /srv/www/dl/readme.txt:
sudo mkdir -p /srv/www/dl
sudo cp -a /srv/files/. /srv/www/dl/
Open the vhost:
sudo vim /etc/nginx/conf.d/files.conf
Replace it with this version, which is the exact file we loaded on the lab VM. The log format writes $uri instead of the file path, and the response header does the same:
log_format filelog '$remote_addr "$request" $status uri=$uri';
server {
listen 8080;
server_name files.example.com;
access_log /var/log/nginx/files.log filelog;
location /dl/ {
root /srv/www;
rewrite ^/dl/v1/(.*)$ /dl/$1 break;
add_header X-Served-File $uri;
}
}
Test the syntax and reload:
sudo nginx -t && sudo systemctl reload nginx
Then request both URLs, the direct one and the one the rewrite handles:
for u in /dl/readme.txt /dl/v1/readme.txt; do curl -s -o /dev/null -w "$u %{http_code}\n" -H "Host: files.example.com" http://127.0.0.1:8080$u; done
Both return 200 now, where the rewritten path returned 500 under the old config on the patched build:
/dl/readme.txt 200
/dl/v1/readme.txt 200
The access log confirms the rewrite resolved both requests to the same file and that no file path is being logged:
127.0.0.1 "GET /dl/readme.txt HTTP/1.1" 200 uri=/dl/readme.txt
127.0.0.1 "GET /dl/v1/readme.txt HTTP/1.1" 200 uri=/dl/readme.txt
Rerun the two audit commands from earlier. On the lab VM the first printed nothing, and the second printed only the rewrite line, which is fine now that no alias shares its location. When the URL layout cannot match the disk layout, keep alias but move the rewrite out of that location and drop every $request_filename reference; that removes the combination the advisory describes, though we only tested the root version. For CVE-2026-93479, F5’s advice is to replace unnamed regex captures in map with named captures and use them only inside the block that does the match. If the host also serves PHP, the nginx with PHP-FPM setup on Ubuntu shows the usual root-based layout, and our nginx install guide for Ubuntu and Debian covers where the stock server blocks live.
Audit checklist for every nginx host
Run this per host, not per fleet, because the config audit is what decides urgency and configs drift between servers built from the same image:
- The installed nginx package version matches or exceeds the fixed version in the table for your release.
- The package changelog names CVE-2026-15176 and CVE-2026-93479 (Ubuntu and Debian), or
rpm -q nginxshows 1.30.6 (Amazon Linux 2023). - The nginx master process started after the package upgrade, not before it.
nginx -Tshows no$request_filenamein anylog_format,setorreturn.- No location combines
aliaswithrewrite. - The error log has no “cannot be used in location” alerts since the upgrade.
- Debian 12 and RHEL hosts carry the config rewrite and stay on a watch list for CVE-2026-15176, where Red Hat says a fix is being pursued (it has deferred the CVE-2026-93479 fix for the RHEL 9 and 10 base package).
Items 4 and 5 are the ones that keep a host safe between advisories, so put them in your config review, not just this week’s patch run. We cover other patch drops for the same stack the same way, such as the PHP2Shell check and patch guide for the PHP side of an nginx and PHP-FPM server. The upstream ranges and fixed releases are on the nginx security advisories page, and Ubuntu’s per-release status is in USN-8955-1.