Blog

nginx-poolslip (CVE-2026-9256): Critical nginx Vulnerability and How to Patch Without Breaking Your Server.

nginx-poolslip
Uncategorized

nginx-poolslip (CVE-2026-9256): Critical nginx Vulnerability and How to Patch Without Breaking Your Server.

WHAT HAPPENED
You open your monitoring dashboard and see a series of nginx worker crashes. No traffic spike, no config errors — workers just keep dying. That could be a sign of active nginx-poolslip exploitation.

In May 2026, NebuSec published details of a critical vulnerability in nginx, named nginx-poolslip and tracked as CVE-2026-9256. CVSS v4.0 score: 9.2 — this is not “patch when convenient”, this is “patch today”.

The vulnerability affects all nginx versions from 0.1.17 through 1.30.1, and version 1.31.0. In practice, that means almost every nginx-powered server in the world.

WHY IT’S DANGEROUS
nginx-poolslip exploits a flaw in memory pool management (ngx_pool_t) through dynamic configuration variables. The attack surface includes the set, map, geo directives and upstream logic.

The impact depends on your configuration and whether ASLR is enabled:

— Without ASLR: Remote Code Execution. An attacker can execute arbitrary code in the context of the nginx worker process.
— With ASLR (standard on Linux): memory corruption causes a worker process crash. Minimum impact — DoS. With an additional bypass — RCE.

Check whether your server is already showing signs of exploitation:

sudo journalctl -u nginx --since "1 hour ago" | grep "worker process exited on signal 11"

An empty result does not necessarily mean everything is clean. There are three possibilities:

— No attacks — everything is genuinely fine.
— nginx crashed, but more than an hour ago — check the full log history:

sudo journalctl -u nginx | grep "worker process exited on signal 11"

— nginx crashed with a different signal — check all worker crashes:

sudo journalctl -u nginx | grep "worker process exited on signal"

If the last command also returns nothing — the server is clean. If there are results — look at the signal number and the timestamp.

If you see signal 11 — your server is already under attack.

AFFECTED VERSIONS
Vulnerable: nginx 0.1.17 through 1.30.1, and nginx 1.31.0.

Fixed versions:
— nginx 1.30.2 (stable branch)
— nginx 1.31.1 (mainline branch)
— NGINX Plus R36 P5, R32 P7, R37.0.1.1

HOW TO CHECK YOUR VERSION

nginx -v

If the version is below 1.30.2 (stable) or 1.31.1 (mainline) — you are vulnerable. Keep reading.

QUICK MITIGATION BEFORE PATCHING
While you prepare to update — verify ASLR is enabled. It does not close the vulnerability, but without an explicit bypass it degrades RCE to DoS:

cat /proc/sys/kernel/randomize_va_space

Should return 2. If not:

echo 2 | sudo tee /proc/sys/kernel/randomize_va_space

To persist across reboots:

echo "kernel.randomize_va_space = 2" | sudo tee /etc/sysctl.d/99-aslr.conf
sudo sysctl -p /etc/sysctl.d/99-aslr.conf

HOW TO UPDATE NGINX

If you’re running Debian or Ubuntu and installed nginx via apt — you likely have the distribution’s bundled package. Ubuntu 24.04 ships nginx 1.24.0, Ubuntu 22.04 ships 1.18.0. Both are vulnerable. Waiting for a distro backport is not a safe option here.

The right approach: add the official nginx.org repository and install from there.

Step 1. Back up your configuration

sudo cp -r /etc/nginx /etc/nginx.bak.$(date +%Y%m%d)
sudo nginx -T > /tmp/nginx-full-config-backup.txt

Step 2. Add the nginx.org GPG key

Download the key to a temporary file:

curl -o /tmp/nginx_signing.key \
  https://nginx.org/keys/nginx_signing.key

Verify the fingerprint before trusting the key. The key is in ASCII-armor format — gpg can read it directly:

gpg --dry-run --quiet --no-keyring \
  --import --import-options show-only \
  /tmp/nginx_signing.key

Expected fingerprints (official, from nginx.org):
8540A6F18833A80E9C1653A42FD21310B49F6B46
573BFD6B3D8FBC641079A6ABABF5BD827BD9BF62
9E9BE90EACBCDE69FE9B204CBCDCD8A38D88A2B3

If the fingerprints match — convert to binary format (APT requires dearmored) and save. The > /dev/null suppresses tee‘s terminal output — the file is written correctly regardless:

gpg --dearmor < /tmp/nginx_signing.key \
  | sudo tee /usr/share/keyrings/nginx-archive-keyring.gpg > /dev/null

If they do not match — delete the file and investigate:

rm /tmp/nginx_signing.key

Step 3. Add the repository

For the stable branch (recommended for production):

echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
https://nginx.org/packages/ubuntu $(lsb_release -cs) nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list

If you are on Debian — replace ubuntu with debian in the URL:

echo "deb [signed-by=/usr/share/keyrings/nginx-archive-keyring.gpg] \
https://nginx.org/packages/debian $(lsb_release -cs) nginx" \
| sudo tee /etc/apt/sources.list.d/nginx.list

Step 4. Pin the repository

Without pinning, apt may fall back to the distribution package on the next update:

cat << 'EOF' | sudo tee /etc/apt/preferences.d/nginx
Package: nginx*
Pin: origin nginx.org
Pin-Priority: 900
EOF

Step 5. Update

sudo apt update

# Check what will be installed before proceeding
apt-cache policy nginx

sudo apt install nginx

In the apt-cache policy nginx output, check the Candidate: line — it should show version 1.30.2 with source nginx.org, not Ubuntu:

nginx:
  Installed: 1.24.0-0ubuntu4
  Candidate: 1.30.2-1~noble
  Version table:
     1.30.2-1~noble 900
        500 https://nginx.org/packages/ubuntu noble/nginx amd64
...

If Candidate still shows the Ubuntu version — pinning did not work, check Step 4.

During installation, apt may prompt about a configuration file:

Configuration file '/etc/nginx/nginx.conf'
==> Modified (by you or by a script) since installation.
==> Package distributor has shipped an updated version.
  What would you like to do about it ? Your options are:
   Y or I  : install the package maintainer's version
   N or O  : keep your currently-installed version

Choose N — keep your version. Your working config is more important than the package default.

Step 6. Verify everything works

After installation, apt automatically restarts nginx — no need to run systemctl restart manually. Just verify:

nginx -v
sudo nginx -t
sudo systemctl status nginx

Expected: nginx/1.30.2, nginx -t passes, service is active.

A NOTE ON YOUR CONFIGURATION FILES
When switching from the Ubuntu package to the nginx.org package, your files in /etc/nginx/ stay intact — provided you answered N to the conffile prompt in Step 5. If you were using the sites-available / sites-enabled structure, it remains in place. Just confirm that nginx -t passes cleanly after the upgrade.

FOR RHEL / ALMALINUX / ROCKY

First try a regular update — if nginx was installed from the official nginx.org repository, this is enough:

sudo dnf update nginx

If nginx was installed from EPEL or another third-party repository, it may not update automatically. Verify:

dnf info nginx | grep Version

If the version is below 1.30.2 — add the official nginx.org repository:

sudo tee /etc/yum.repos.d/nginx.repo << 'EOF'
[nginx-stable]
name=nginx stable repo
baseurl=http://nginx.org/packages/centos/$releasever/$basearch/
gpgcheck=1
enabled=1
gpgkey=https://nginx.org/keys/nginx_signing.key
module_hotfixes=true
EOF

sudo dnf update nginx

On the first update, DNF will download the GPG key and ask for confirmation — it will display the fingerprint. Compare it against the same three official fingerprints listed above in the Ubuntu section. Only then type y.

SUMMARY
nginx-poolslip is a serious vulnerability with a CVSS score of 9.2. The patch is already available. The update takes five minutes. The only things that can go wrong are skipping the config backup or trusting a GPG key without verifying its fingerprint.

Patch today.

Leave your thought here

Your email address will not be published. Required fields are marked *