This is a peephole in the loading dock, not a front-door break-in
Tenable plugin 118151 maps to CVE-2017-7529: an integer overflow in NGINX's range filter. Upstream says affected versions are 0.5.6 through 1.13.2, fixed in 1.12.1 and 1.13.3. A remote attacker sends a crafted Range request; with standard modules, the practical outcome is disclosure of a cache file header when the response was served from cache, which can expose backend IPs or similar metadata.
The vendor's MEDIUM judgment matches reality better than the scanner's HIGH/CVSS 7.5 framing. The headline CVSS assumes pure network reachability and high confidentiality impact, but the real exploit chain narrows fast: you need an internet-facing NGINX, caching enabled, a cacheable object already stored, and a response path where leaking the cache header matters. That's not fake risk, but it is not the same as a no-friction, full-content data theft bug.
4 steps from start to impact.
Fingerprint an exposed NGINX edge
curl, httpx, or nginxpwner to identify NGINX on an internet-facing host and infer a vulnerable build from the Server header or response behavior. Tenable's own plugin also keys off the Server header, which means detection is often version-based rather than exploit-confirmed.- Target must be internet-reachable over HTTP/S
- NGINX must disclose a version or be fingerprintable
- Many deployments suppress or rewrite the
Serverheader - Reverse proxies, CDNs, OpenResty/Tengine, and vendor backports muddy version detection
Find a cacheable object and force a cache hit
proxy_cache/fastcgi_cache/similar that is both cacheable and already cached, then issue a malformed multi-range request that hits the vulnerable range filter path.- Caching must be enabled for the target path
- A suitable response must already exist in cache or be made cacheable
- A lot of enterprise NGINX deployments are reverse proxies without disk caching on sensitive paths
- Auth, cache-control headers, short TTLs, and path-specific cache bypass rules reduce reachable population
Range patterns, but most orgs do not alert on them by default.Leak cache metadata through the range parser
- The crafted request must traverse the vulnerable range filter path
- The response must be served from cache
- Impact is confidentiality-only in the normal case
- Leaked data is often low-grade infrastructure metadata, not customer records
Use the leaked metadata for follow-on targeting
- Leaked metadata must reveal something operationally useful
- Attacker must have another path to capitalize on that information
- Many leaks are low-value and do not materially change attacker capability
- Modern segmentation, private origins, and EDR on backend systems still block the next stage
max_ranges 1; — Apply the upstream temporary workaround on exposed NGINX tiers where patching is not immediate. This constrains the vulnerable range-processing path and is the most direct config mitigation; for a MEDIUM verdict there is no noisgate mitigation SLA, so deploy it in the next normal change window where risk justifies it.proxy_cache, fastcgi_cache, and similar directives and turn them off for authenticated, tenant-specific, or infrastructure-revealing responses. The exploit path depends on cached responses; removing cacheability collapses the most important prerequisite, and for MEDIUM there is no noisgate mitigation SLA.Range requests — Log and hunt for malformed or excessive multi-range requests against NGINX edges. This will not patch the flaw, but it gives you cheap visibility into reconnaissance and opportunistic probing; again, no noisgate mitigation SLA applies to a MEDIUM finding.- Hiding the
Serverheader does not fix the bug; it only makes version-based scanning noisier. - TLS termination does nothing here; the malicious
Rangerequest is valid application traffic after decryption. - A generic WAF rule set without explicit
Rangenormalization or anomaly logic is unreliable; many WAFs simply pass these requests upstream.
The supporting signals.
| In-the-wild status | No solid evidence of broad active exploitation found, and not listed in CISA KEV based on catalog review/search context as of 2026-06-02. |
|---|---|
| PoC / testing availability | Public testing exists. stark0de/nginxpwner explicitly tests for CVE-2017-7529; Loginsoft also published a Sigma rule for exploitation attempts. |
| EPSS | High predictive score despite the narrow practical chain: 0.91959 / 91.91%, 100th percentile in public EPSS mirrors. |
| KEV status | Not KEV-listed as of 2026-06-02. |
| CVSS vector | CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N — the score is driven by internet reachability and confidentiality impact, but it does not model the crucial cache-hit prerequisite. |
| Affected versions | Upstream NGINX says vulnerable: 0.5.6–1.13.2. |
| Fixed versions | Upstream fix is 1.12.1 or 1.13.3. Debian and Ubuntu ship backports; for example Debian lists fixes such as 1.10.3-1+deb9u1 and later distro builds rather than forcing upstream-version parity. |
| Exposure / footprint | BitSight's public footprint page shows a large global observation set for this CVE and 176,291 US observations alone, which means the product class is everywhere even if the vulnerable subset is smaller. |
| Disclosure timeline | Upstream advisory published 2017-07-11; NVD published 2017-07-13; Tenable plugin 118151 was published 2018-10-16 and updated 2025-04-15. |
| Reporter / provenance | Red Hat's tracking bug shows Adam Mariš reported the issue on 2017-07-07; the bug acknowledges the NGINX project. |
Sources.
Why this verdict
- Down-pressure: cache hit required — exploitation is not just 'send packet, get data'; the target path must be served from NGINX cache, which many enterprises limit or disable on sensitive traffic.
- Down-pressure: normal impact is narrow — upstream says standard-module exploitation leaks a cache file header; the common output is backend IPs or metadata, not turnkey full-response theft or RCE.
- Up-pressure: unauthenticated and remote — if you do run exposed cached NGINX edges, the attack is cheap, public testing exists, and no credentials or prior foothold are required.
Why not higher?
Because this is not a broad, one-request compromise primitive. The attacker needs a reachable cached object and, in the common case, only gets metadata leakage from the cache header path; there is no strong evidence here of active KEV-class abuse or mainstream post-exploitation automation.
Why not lower?
Because the bug is still remotely reachable on internet-facing infrastructure and requires no authentication. In environments that do use proxy or FastCGI caching, backend IP disclosure and cache internals can meaningfully help recon, routing abuse, and follow-on targeting.
Crowdsourced verification payload.
Run this on the target Linux host that actually serves NGINX traffic, not from an auditor workstation. Invoke it as sudo bash check-cve-2017-7529.sh or sudo bash check-cve-2017-7529.sh /usr/sbin/nginx; root is recommended so RPM changelogs and package metadata are readable. The script prints VULNERABLE, PATCHED, or UNKNOWN and exits 1, 0, or 3 respectively.
#!/usr/bin/env bash
# check-cve-2017-7529.sh
# Determine likely exposure to NGINX CVE-2017-7529 on a Linux host.
# Exit codes: 0=PATCHED, 1=VULNERABLE, 3=UNKNOWN
set -u
BIN="${1:-nginx}"
say() { printf '%s\n' "$*"; }
ver_ge() {
# returns 0 if $1 >= $2
[ "$(printf '%s\n%s\n' "$1" "$2" | sort -V | tail -n1)" = "$1" ]
}
ver_lt() {
# returns 0 if $1 < $2
! ver_ge "$1" "$2"
}
if ! command -v "$BIN" >/dev/null 2>&1; then
say "UNKNOWN: nginx binary not found: $BIN"
exit 3
fi
raw_ver="$($BIN -v 2>&1 | sed -n 's#.*nginx/\([^ ]*\).*#\1#p')"
up_ver="$(printf '%s' "$raw_ver" | grep -oE '[0-9]+(\.[0-9]+){1,2}' | head -n1)"
if [ -z "$up_ver" ]; then
say "UNKNOWN: could not parse nginx version from: $raw_ver"
exit 3
fi
# 1) Debian / Ubuntu package checks (prefer distro backports over upstream-string logic)
if command -v dpkg-query >/dev/null 2>&1 && command -v dpkg >/dev/null 2>&1; then
for pkg in nginx nginx-core nginx-full nginx-light nginx-extras; do
pkgver="$(dpkg-query -W -f='${Version}' "$pkg" 2>/dev/null)"
if [ -n "$pkgver" ]; then
# Debian fixed versions
if dpkg --compare-versions "$pkgver" ge "1.22.1-9+deb12u7" || \
dpkg --compare-versions "$pkgver" ge "1.18.0-6.1+deb11u6" || \
dpkg --compare-versions "$pkgver" ge "1.10.3-1+deb9u1" || \
dpkg --compare-versions "$pkgver" ge "1.6.2-5+deb8u5" || \
dpkg --compare-versions "$pkgver" ge "1.2.1-2.2+wheezy4+deb7u1"; then
say "PATCHED: Debian-family package $pkg version $pkgver includes a fixed build for CVE-2017-7529"
exit 0
fi
# Ubuntu fixed versions from vendor advisories
if dpkg --compare-versions "$pkgver" ge "1.10.3-1ubuntu3.1" || \
dpkg --compare-versions "$pkgver" ge "1.10.3-0ubuntu0.16.04.2" || \
dpkg --compare-versions "$pkgver" ge "1.10.1-0ubuntu1.3" || \
dpkg --compare-versions "$pkgver" ge "1.4.6-1ubuntu3.8"; then
say "PATCHED: Ubuntu-family package $pkg version $pkgver includes a fixed build for CVE-2017-7529"
exit 0
fi
# If package exists but is older than known fixed distro versions, fall through to upstream logic.
break
fi
done
fi
# 2) RPM-family package checks: changelog is the safest generic backport signal
if command -v rpm >/dev/null 2>&1; then
for pkg in nginx nginx-core nginx-all-modules rh-nginx110-nginx; do
if rpm -q "$pkg" >/dev/null 2>&1; then
if rpm -q --changelog "$pkg" 2>/dev/null | grep -q 'CVE-2017-7529'; then
say "PATCHED: RPM package $pkg changelog references CVE-2017-7529 (backport/fix present)"
exit 0
fi
# Known Red Hat SCL fixed build from RHSA-2017:2538
nevra="$(rpm -q --qf '%{VERSION}-%{RELEASE}\n' "$pkg" 2>/dev/null)"
if [ "$pkg" = "rh-nginx110-nginx" ] && [ -n "$nevra" ]; then
if [ "$nevra" = "1.10.2-8.el7" ] || ver_ge "$nevra" "1.10.2-8.el7"; then
say "PATCHED: $pkg $nevra is at or above the RHSA-2017:2538 fixed build"
exit 0
fi
fi
break
fi
done
fi
# 3) Upstream version logic for source builds / nginx.org packages
# Affected: 0.5.6 through 1.13.2
# Fixed: 1.12.1+ on stable branch, 1.13.3+ on mainline branch
if ver_lt "$up_ver" "0.5.6"; then
say "PATCHED: upstream version $up_ver predates the affected range"
exit 0
fi
if ver_ge "$up_ver" "1.13.3"; then
say "PATCHED: upstream version $up_ver is fixed"
exit 0
fi
if ver_ge "$up_ver" "1.13.0" && ver_lt "$up_ver" "1.13.3"; then
say "VULNERABLE: upstream version $up_ver is in the affected mainline range (1.13.0-1.13.2)"
exit 1
fi
if ver_ge "$up_ver" "1.12.1" && ver_lt "$up_ver" "1.13.0"; then
say "PATCHED: upstream stable version $up_ver is fixed"
exit 0
fi
if ver_ge "$up_ver" "0.5.6" && ver_lt "$up_ver" "1.12.1"; then
say "VULNERABLE: upstream version $up_ver is in the affected stable range (0.5.6-1.12.0)"
exit 1
fi
say "UNKNOWN: unable to confidently map installed build to vendor-fixed package data"
exit 3