NGINX security updates: CVE fixes in 1.30.6 and 1.31.7, and how to upgrade
The NGINX releases of 14 October fix five config-dependent flaws: how to check your real version, what to review and how to pin it.
This article is educational and does not replace a formal smart contract audit, legal advice, financial advice, or protocol-specific security review.
On 14 October 2026, the nginx project released new versions of its stable and mainline branches. Both fix five medium-severity vulnerabilities in NGINX, and four of them affect versions released years ago. Each one can only be triggered by a specific configuration, for example HTTP/3 or alias with rewrite.
If you serve production traffic with NGINX Open Source, upgrade to the new stable or mainline release, or to your distribution's patched package. Reviewing the configuration helps you decide the order, not stay on an affected version: configurations change over time, and the patched version no longer depends on that analysis.

This article explains what the new versions fix, how to find out which NGINX you really run on servers, packages and container images, which directives are worth looking for and how to pin the new version so that it cannot regress. At the end, a real case with Node.js shows the same pattern applied to another component.
What 1.30.6 and 1.31.7 fix
The fixed versions are nginx 1.30.6, on the stable branch, and nginx 1.31.7, on the mainline branch. According to the nginx.org changelog, these are the five fixes of 14 October:
- CVE-2026-15176: buffer overflow in a worker process when the alias directive serves a URI that rewrite changed before. Affects 0.1.29 to 1.31.6.
- CVE-2026-93479: buffer overflow while evaluating expressions with variables, which is involved in the root calculation and in the logs of the http and stream modules. Affects 1.30.0 to 1.30.5 and 1.31.2 to 1.31.6.
- CVE-2026-95101: with HTTP/3, part of an unknown frame can be treated as the request body, which allows bypassing client_max_body_size or injecting data into the request sent to the backend. Affects 1.25.0 to 1.31.6.
- CVE-2026-97629: when rotating the TLS session ticket keys, one of them was left uninitialized, which could allow forging a session. Affects 1.23.2 to 1.31.6.
- CVE-2026-97205: with asynchronous file I/O (aio), an SSI page with include virtual commands can cause a use-after-free. Affects 0.8.11 to 1.31.6.
nginx.org rates them as medium severity. F5, which assigns the NGINX CVEs, publishes CVSS 3.1 scores between 5.3 and 8.1 in the NVD. As of 23 October, the NVD had not yet done its own analysis of any of the five.
If you are coming from a version older than 1.30.4, the upgrade also brings earlier fixes. The most relevant is CVE-2026-42533, which nginx.org rates as major and fixed on 15 July in 1.30.4: a memory overflow when map with regular expressions is combined with a capture of that map. The 1.31.8 mainline release, of 21 October, adds no security fixes.
- nginx: security advisories
- nginx: CHANGES-1.30 (stable branch)
- nginx: CHANGES (mainline branch)
- NVD: CVE-2026-15176
- NVD: CVE-2026-93479
- NVD: CVE-2026-95101
- NVD: CVE-2026-97629
- NVD: CVE-2026-97205
- NVD: CVE-2026-42533
Why upgrade even if your configuration does not trigger them
Each of these vulnerabilities needs a specific combination: alias with rewrite, HTTP/3, TLS ticket rotation, aio with SSI. It is tempting to review the configuration, not find those directives and leave the version as it is. There are three reasons not to.
The first is that configurations move. A new include, a template from another team or turning on HTTP/3 on one server can reopen the exposure without anyone looking at the advisory again. The patched version does not depend on that analysis staying true.
The second is cost. 1.30.6 belongs to the same branch as 1.30.5, and its changelog lists only fixes and a change in the level of some log messages, with no new features. On the stable branch, upgrading is usually cheaper than keeping and justifying an exception.
The third is that older branches do not get these patches from nginx.org. The download page lists 1.28, 1.26 and others as legacy versions, and the advisory marks only 1.30.6 and 1.31.7 onwards as fixed. If you use one of those branches, the way out is 1.30.6 or your distribution's patched package.
Step 1: find out which NGINX you really run
The version that matters is that of the binary that serves the traffic, and it does not always match the one in a README or in an image tag.
# Binary version
nginx -v
# Compiled-in modules: HTTP/3 shows up as --with-http_v3_module
nginx -V 2>&1 | tr ' ' '\n' | grep -E 'http_v3|file-aio|threads'
# Debian and Ubuntu: the package version is what tells you whether the patch is applied
apt-cache policy nginx
# Containers: real version inside the image
docker run --rm nginx:1.30.6-alpine nginx -vWith distribution packages, the number from nginx -v can mislead. Distributions often apply the patch on top of their version without changing the main number. On Debian 13, for example, the package that fixes the five October CVEs is 1.26.3-3+deb13u10, according to advisory DSA-6575-1, and nginx -v still shows 1.26.3. What you need to compare is the full package version with the one in your distribution's advisory.
On Kubernetes, an ingress controller or a third-party image can ship its own NGINX build. The nginx.org page, for example, tells its NGINX Ingress Controller apart from the community project ingress-nginx. In those cases, the patched version is published by whoever maintains the controller or the image.
Step 2: check which directives the configuration uses
nginx -T validates the configuration and prints all of it, with every include resolved. Filtering it with grep gives a first list of the directives related to this year's advisories:
# Full configuration (includes resolved), filtered by the directives in the advisories.
# Line numbers are those of the nginx -T output, not of each file.
sudo nginx -T 2>/dev/null | grep -nE '^\s*(alias|rewrite|map|aio|ssi|http3|ssl_session_cache|ssl_session_ticket_key)\b|\$request_filename|\bquic\b'How to read the result, according to the descriptions F5 publishes in the NVD for each CVE:
- A location with alias together with rewrite and a set or return directive that references the $request_filename variable, or $request_filename in the access log format (log_format), point to CVE-2026-15176.
- A map with regular expressions whose capture variables appear in root or in the access log format before the map output variable points to CVE-2026-93479. If they appear that way in any expression with variables, they point to CVE-2026-42533.
- listen with quic, or http3 on, point to CVE-2026-95101.
- ssl_session_cache shared without ssl_session_ticket_key points to CVE-2026-97629.
- aio together with ssi points to CVE-2026-97205.
A match does not confirm that the vulnerability can be exploited, and the absence of a match does not fully rule it out: grep does not see third-party modules or configurations generated at startup. It is a way to order the work. Servers with matches go first, and the rest are upgraded anyway.
Step 3: upgrade and pin the version
On servers with packages, the upgrade is the usual one for each system: install the new package, validate with nginx -t and restart the service so that the new binary serves the traffic. According to the nginx documentation, a reload only rereads the configuration; switching binaries needs a restart or the on-the-fly upgrade with the USR2 signal.
In containers, pin the image by tag and by digest. The tag says which version you wanted, and the digest pins exactly the image you reviewed, even if someone publishes the tag again.
# Readable tag and immutable digest.
# Get the digest with: crane digest nginx:1.30.6-alpine
FROM nginx:1.30.6-alpine@sha256:47928bf67eb62a1863cb08d9ecb52d3e704304ba614eaee17884204677702951The digest in this example is the one the tag returned on 23 October 2026. A tag can be published again with different content, for example when the image is rebuilt, so get the digest at the moment you pin it.
To keep the version from regressing, a CI check can fail if any Dockerfile or manifest uses an NGINX image older than the fixed one:
#!/usr/bin/env bash
# Fails if any Dockerfile or YAML manifest uses an NGINX image older than 1.30.6 (stable) or 1.31.7 (mainline).
set -euo pipefail
refs=$(grep -rhoE --include='Dockerfile*' --include='*.yaml' --include='*.yml' \
'(nginx|nginxinc/nginx-unprivileged):[0-9]+\.[0-9]+(\.[0-9]+)?' . | sort -u || true)
bad=0
for ref in $refs; do
ver=${ref##*:}
IFS=. read -r major minor patch <<< "$ver"
patch=${patch:-0}
if (( major < 1 || ( major == 1 && ( minor < 30 || (minor == 30 && patch < 6) || (minor == 31 && patch < 7) ) ) )); then
echo "Needs update: $ref"; bad=1
fi
done
exit $badThe script only recognizes tags with a version number. Floating tags such as stable-alpine or latest have no number to compare, which is one more reason to pin version and digest.
A real case: the same pattern with Node.js
On 21 October, Node.js released versions 24.22.1, 22.23.4 and 26.12.1. They fix several vulnerabilities, the most serious of high severity according to the project itself, and they update the root certificates to NSS 3.131.1, an update that the Node.js advisory links to the compromise of an eMudhra intermediate CA.
The eMudhra compromise has its own article on what to update in the developer tools on macOS.
A Node.js project in production, with several container images, already has that update in its development branch, with three pieces that work the same way for NGINX:
- All its images moved to node:24.22.1-alpine, pinned by tag and by digest.
- An auxiliary image that carried its own Node 22 and an old base image with Node 20 moved to the same version.
- The package.json declares engines.node with the value >=24.22.1, and CI has checks that reject images with an older version.
# Node version inside the image, without starting the application
docker run --rm node:24.22.1-alpine node -v
# Digest to pin the image
crane digest node:24.22.1-alpine
# Patched 24.x line only (>=24.22.1 <25); with --engine-strict, npm install fails on any Node outside that range
npm pkg set engines.node='^24.22.1'
npm install --engine-strictThe lesson carries over as is. A security update does not end when a line is changed: it ends when the version is pinned in the image, declared in the project and checked in CI, so that a later change cannot undo it without anyone noticing.
What this update does not cover
If NGINX is not yours, neither is the patch. A CDN or a managed platform that puts its own proxy in front of your application has it updated by its provider, and your job is to know which components you do manage. It does not cover other products of the family either: njs, for example, published its own version 1.0.2 on the same day, 14 October, with different fixes.
Upgrade, pin and verify
The 14 October advisories call for finishing the job, not for a rushed reaction: know which NGINX serves the traffic, upgrade, pin the image by digest and keep a verification step in CI that stops older versions from coming back.
If you want to discuss how to apply this process to your infrastructure, you can write to us from the contact page; in the message, mention this article, without credentials or sensitive configuration details.
Source registry
Sources consulted on 23 October 2026. Run on Linux, with the output saved: nginx -v and nginx -V on the nginx.org 1.30.6 package and the Debian 13 1.26.3 package; nginx -T and the directive filter on a test configuration; the CI script on test manifests; crane digest for the images in the article; the NGINX and Node versions inside the nginx:1.30.6-alpine and node:24.22.1-alpine images, extracted with crane; npm pkg set and npm install --engine-strict. Not run: docker run, replaced by extracting the image with crane, and the upgrade and restart of the service on a server.
- nginx: security advisories
- nginx: CHANGES-1.30
- nginx: CHANGES
- nginx: news
- nginx: download
- nginx: controlling nginx
- NVD: CVE-2026-15176
- NVD: CVE-2026-93479
- NVD: CVE-2026-95101
- NVD: CVE-2026-97629
- NVD: CVE-2026-97205
- NVD: CVE-2026-42533
- Debian security tracker: DSA-6575-1
- Docker Hub: official nginx image
- Node.js: October 21, 2026 Security Releases
- Node.js 24.22.1 (LTS)
- crane (go-containerregistry)
Need help applying this to your launch or workflow?
Request a technical review and we will map the safest first step.


