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
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. |
noisgate verdict.
The decisive down-pressure is the cache requirement: this is only materially exploitable where an exposed NGINX tier both caches eligible responses and leaks useful metadata from the cache header path. That sharply reduces the real exposed population versus the raw CVSS story, and the normal-case impact remains confidentiality-only metadata disclosure, not direct code execution or account compromise.
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.
What to do — in priority order.
- Set
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. - Disable caching on sensitive paths — Review
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. - Alert on anomalous
Rangerequests — 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. - Prefer package backports from vendor repos — On Debian/Ubuntu/RHEL-derived fleets, verify fixed distro builds instead of chasing upstream version strings only. This avoids false positives and gets you the security fix through supported packaging; with MEDIUM, go through standard maintenance rather than emergency change.
- 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.
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
If you remember one thing.
max_ranges 1; in the next normal change window. For a MEDIUM verdict there is no noisgate mitigation SLA — go straight to the 365-day remediation window; use the noisgate remediation SLA to get vendor-fixed packages or supported distro backports rolled out within 365 days.Sources
What defenders are saying.
Crowdsourced verification outputs.
Results submitted by users who ran the verification payload against their environment.