Visit NES for NGINX Home Page

NES for NGINX Release Notes

Comprehensive release notes and changelog for NES for NGINX, including security patches, bug fixes, and feature updates across all supported versions.

7 Patched Vulnerabilities
VEX Statements

October 2026

Release: v1.31.7-nes-1.31.2, NGINX 1.31.7, with njs 1.0.2 (QuickJS 2026.06.04) in nginx-module-njs.

Packages: signed RPMs for RHEL 8, 9 and 10 on x86_64 and aarch64, at https://registry.nes.herodevs.com/bin/nes/nginx/v1.31.7-nes-1.31.2/ (see Installation).

This release fixes the following CVEs:

NGINX

  • CVE-2026-15176 (CVSS 3.1: 8.1 High; CVSS 4.0: 9.2 Critical), HTTP core (alias, rewrite): Heap buffer overflow in a worker process. After rewrite changed the URI, and before a new location was chosen, $request_filename still mapped the new URI through the current location's alias; a rewritten URI shorter than the location prefix overflowed the path buffer, a longer one was mapped to the wrong file. Vulnerable 0.1.29-1.31.6; fixed upstream in 1.31.7 and 1.30.6. Advisories: nginx.org (medium), F5 K000162416. Fix: nginx 1.31.7, which nginx-nes is based on from v1.31.7-nes-1.31.2: nginx/nginx f8a23425bd68: ngx_http_map_uri_to_path() refuses to map while r->uri_changed is set. Reachability: Reachable only with alias and a rewrite without break in the same location, and $request_filename evaluated before the location changes: in return, set, if or add_header there, or in that location's access log format. The packaged configuration uses root, so not by default. Earlier NES builds are affected, though since the DAV alias backport they refuse a rewritten URI shorter than the prefix ("URI shorter than aliased URI part"), so only the wrong-file mapping remained there.
  • CVE-2026-93479 (CVSS 3.1: 8.1 High; CVSS 4.0: 9.2 Critical), Script engine (ngx_http_script.c, ngx_stream_script.c): Heap buffer overflow in a worker process. When a string expression with variables evaluated longer than its length pass predicted, ngx_http_script_run() and ngx_stream_script_run() let the copy spill into the space the caller reserved; the caller then wrote past the end of the buffer by up to that reserved size (for the document root, the length of the URI; for an access log file path, one NUL byte). Vulnerable 1.31.2-1.31.6 and 1.30.0-1.30.5; fixed upstream in 1.31.7 and 1.30.6. Advisories: nginx.org (medium), F5 K000162607. Fix: nginx 1.31.7, which nginx-nes is based on from v1.31.7-nes-1.31.2: nginx/nginx 6aa4b3fdd4fd: the copy is bounded by the evaluated length, not by the length plus the reserved space. Reachability: Reachable when a root or alias with variables is used to map a request to a file (static files and $request_filename, through ngx_http_map_uri_to_path(), or $realpath_root), or an access_log file path in http or stream has variables, and those variables change between the two passes: a regex capture used before a map that matches by regex (which replaces the captures), or a non-cacheable variable. Not in the packaged configuration.
  • CVE-2026-95101 (CVSS 3.1: 5.3 Medium; CVSS 4.0: 6.9 Medium), HTTP/3 (ngx_http_v3_module): Request body injection. The HTTP/3 request body parser kept the remaining length of an unknown (skipped) frame in the field the body filter uses for DATA payload; when such a frame was split across reads, its remainder was passed on as request body, unframed, bypassing client_max_body_size (checked only on DATA frames) and injecting data into the proxied request. Vulnerable 1.25.0-1.31.6; fixed upstream in 1.31.7 and 1.30.6. Advisories: nginx.org (medium), F5 K000162613. Fix: nginx 1.31.7, which nginx-nes is based on from v1.31.7-nes-1.31.2: nginx/nginx 1c173a2d8767: the skipped length is kept in its own st->skip counter. Reachability: Reachable only on an HTTP/3 listener (listen ... quic) that reads request bodies, such as proxying with request buffering (F5 names proxy_request_buffering on, the default). The packages are built --with-http_v3_module, but the packaged configuration has no QUIC listener.
  • CVE-2026-97629 (CVSS 3.1: 6.5 Medium; CVSS 4.0: 8.3 High), SSL session tickets (ngx_event_openssl.c): Session forgery. With automatic session ticket key rotation, each worker synced only two of its three ticket key slots from shared memory; the third kept uninitialized memory and was still matched by key name when decrypting, so a ticket naming it could be accepted with uninitialized key material, forging a session (F5: possibly bypassing client certificate verification). Vulnerable 1.23.2-1.31.6; fixed upstream in 1.31.7 and 1.30.6. Advisories: nginx.org (medium), F5 K000162606. Fix: nginx 1.31.7, which nginx-nes is based on from v1.31.7-nes-1.31.2: nginx/nginx 1916f26e6ca4: all key slots are synced to the worker. Reachability: Reachable on SSL servers (http, stream, mail) with ssl_session_cache shared:... and no ssl_session_ticket_key (session tickets are on by default), the configuration that rotates ticket keys automatically. Whether a forged ticket is accepted depends on the uninitialized memory, which the attacker does not control. The packaged configuration has no SSL server.
  • CVE-2026-97205 (CVSS 3.1: 8.1 High; CVSS 4.0: 9.2 Critical), HTTP core, asynchronous file I/O (ngx_http_copy_filter_module.c, ngx_http_file_cache.c, ngx_http_upstream.c): Use-after-free in a worker process. Each pending asynchronous file operation holds a reference in the request's 8-bit blocked counter, which was not checked; 256 operations pending on one request, for example an SSI page with many include virtual commands, wrapped it to zero and the request could be freed while they still used its memory. Vulnerable 0.8.11-1.31.6; fixed upstream in 1.31.7 and 1.30.6. Advisories: nginx.org (medium), F5 K000162608. Fix: nginx 1.31.7, which nginx-nes is based on from v1.31.7-nes-1.31.2: nginx/nginx 6adfc05ece48: at most 250 pending operations per request (NGX_HTTP_MAX_BLOCKED); beyond that, reads are synchronous or refused. Reachability: Reachable only with aio on or aio threads (the packages are built --with-file-aio and --with-threads; aio is off by default) and pages that start many file reads on one request, such as SSI include virtual. Not in the packaged configuration.

njs and QuickJS

  • CVE-2026-101025 (CVSS 3.1: 5.3 Medium; CVSS 4.0: 6.9 Medium), njs: The built-in njs engine leaks a libxml2 parser context when xml.parse() fails; the failure path never registered cleanup, so the context is never released. Repeated malformed XML input exhausts worker process memory. Fix: njs 1.0.2 pin bump (packaging/sources.json, MODULE_VERSIONS.md). Reachability: njs XML module used by the customer's js code.
  • CVE-2026-101019 (CVSS 3.1: 6.5 Medium; CVSS 4.0: 8.3 High), njs: The njs XML module exposes entity-backed XML attributes inconsistently with libxml2 canonicalization in both the built-in njs and QuickJS backends: the $attr$Name getter can return undefined for an attribute that contains an internal entity reference, and $attrs can return a value derived from only the first attribute child. Affects signed XML validation (confirmed with nginx-saml on the built-in njs backend). Fix: njs 1.0.2 pin bump (packaging/sources.json, MODULE_VERSIONS.md). Reachability: njs XML module used by the customer's js code.

Upgrade notes

This release moves nginx from 1.31.6 to 1.31.7, the upstream release that fixes this release's five nginx CVEs, and updates njs in nginx-module-njs from 1.0.1 to 1.0.2. Check the following before upgrading.

nginx 1.31.7 (see the nginx 1.31.7 changes):

  • A buffer size directive set to 0 is now a configuration error: nginx -t fails, and nginx does not start or reload, with any of client_body_buffer_size, client_header_buffer_size, subrequest_output_buffer_size, proxy_buffer_size, fastcgi_buffer_size, grpc_buffer_size, memcached_buffer_size, scgi_buffer_size, uwsgi_buffer_size, tunnel_buffer_size, ssl_buffer_size, http3_stream_buffer_size, mp4_buffer_size, mp4_max_buffer_size, preread_buffer_size or the mail module's proxy_buffer set to 0.
  • When nginx verifies a backend's certificate (proxy_ssl_verify, grpc_ssl_verify, uwsgi_ssl_verify, and proxy_ssl_verify in stream) against a name that is an IP address, only iPAddress subjectAltName entries match it now; a certificate that has the address only in a dNSName entry or the commonName fails verification.
  • HTTP/2 now prioritizes responses with the RFC 9218 scheme (the Priority request header and PRIORITY_UPDATE frames) and ignores RFC 7540 priority signals.
  • An SSL connection closed without close_notify, a reset one included, is no longer treated as a clean shutdown: such connections now log "SSL_read() failed" errors.

njs 1.0.2 changes the njs XML API (the xml module). Check js code that uses it:

  • XML node mutation and canonicalization reject detached nodes, and a removed child node has an undefined $parent.
  • Text and attribute values must be primitive strings; null and undefined keep their deletion semantics.
  • addChild() and $tags reject source trees with namespaces.
  • In the QuickJS engine, assigning to $tag$name throws a TypeError; deleting it still works.

njs 1.0.2 also adds XMLNode.getAttributeNS() and XMLNode.getChildNS() for namespace-aware lookups, and ngx.fetch() now rejects responses with conflicting Content-Length fields, with both Transfer-Encoding and Content-Length, or with a 1xx status code. See the njs 1.0.2 changes.

From this release on, every RPM's file name carries the whole release: <package>-v1.31.7-nes-1.31.2.el<RHEL version>.<architecture>.rpm, for example nginx-v1.31.7-nes-1.31.2.el9.x86_64.rpm, where v1.31.6-nes-1.31.1 used the package's version and release (nginx-1.31.6-1.nes.el9.x86_64.rpm). The signing key and checksum files keep their names. Update scripts that download the RPMs by name. The packages themselves are named and versioned as before (rpm -q nginx shows nginx-1.31.7-2.nes.el9.x86_64 on RHEL 9), so dnf install upgrades v1.31.6-nes-1.31.1 as usual.