nginx-poolslip (CVE-2026-9256): Critical nginx Vulnerability and How to Patch Without Breaking Your Server.
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):8540A6F18833A80E9C1653A42FD21310B49F6B46573BFD6B3D8FBC641079A6ABABF5BD827BD9BF629E9BE90EACBCDE69FE9B204CBCDCD8A38D88A2B3
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.
