Releases: dvershinin/gixy
v0.2.48
Fixed
- Circular
includedirectives no longer crash the parser (#113, fixed in #115). nginx configs with an include cycle β most commonly a file in/etc/nginx/conf.d/whose body saysinclude /etc/nginx/conf.d/*.conf;(the glob matches the including file itself), or AβB mutual includes β used to sendNginxParserinto unbounded recursion. On Python 3.11+ with enough stack budget that surfaced asRecursionError; on others the cycle silently inflated the parsed tree with hundreds of duplicated directives. The parser now tracks the canonical path of every file currently being parsed and skips any include that re-enters one already on the stack, emitting a singleSkipping circular include: β¦WARNING per cycle. Applies to both filesystem includes andnginx -Tdump-mode includes.
Full changelog: https://github.com/dvershinin/gixy/blob/master/CHANGELOG.md
v0.2.47
Added
nginx_cves: New entry CVE-2026-9256 β heap memory buffer overflow inngx_http_rewrite_moduletriggered by a configuration with overlapping captures, potentially resulting in arbitrary code execution in a worker process. Affects nginx OSS0.1.17..1.31.0. Mitigation: upgrade to 1.31.1 (mainline) or 1.30.2 (stable). The check fires purely on--nginx-version=match β--nginx-version=1.31.0(previously considered patched) now reports this CVE. Advisory: https://nvd.nist.gov/vuln/detail/CVE-2026-9256, nginx CHANGES-1.30: https://nginx.org/en/CHANGES-1.30. Credit: Mufeed VH of Winfunc Research.
Full changelog: https://github.com/dvershinin/gixy/blob/v0.2.47/CHANGELOG.md
v0.2.46
Fixed
-
originsfalse positive on host regexes anchored with($|/)(#111): A regex like^https?://example\.com($|/)(?P<path>.*)was reported as matching the bypasshttp://example.com$aaaaa.evil.com, even though that string does not actually match β the$in($|/)is the end-of-string anchor, not a literal$.Root cause was in
gixy/core/regexp.py:AtToken.generate()emitted the raw^/$characters, and when an end anchor lived inside an alternation whose group had sibling tokens (e.g. the trailing(?P<path>.*)),_gen_combinatorhappily produced candidates with$stranded mid-string. Theoriginsplugin then mutated these impossible-match candidates into bogus bypass URLs.Switched anchors to sentinel characters during generation; candidates with interior anchors are dropped at the top-level yielder before any plugin sees them. Semantically-equivalent regex rewrites now produce identical candidate sets.
Thanks to @realpixelcode for the detailed reproduction and follow-up.
v0.2.45
Fixed
- Named regex capture groups in
ifblocks:gixyno longer logs a spuriousCan't find variable 'name'INFO for configs likeif ($http_referer ~ "^https?://example\.com(?P<path>.*)") { set $x $path; }. Server-scope prepopulate was descending intoIfBlockto evaluate innersetdirectives before the if's regex capture groups had been registered; the block's ownprovide_variablesare now registered before recursion (#111). - Crash on Python 3.11+ for regexes generating invalid DNS labels:
gixy/plugins/origins.pycalledcandidate_match.encode("idna")without protection. Python >= 3.11 idna codec rejects strings with empty or over-long labels (e.g. a regex containing\.\.or a 64+ char run), aborting the entire audit withUnicodeError: label empty or too long. The call is now guarded; on failure the raw candidate is used and downstreamparse_urldecides (#111).
v0.2.44
Fixed
- Builtin variable table refresh: Recognize 13 nginx variables that were missing from
gixy/core/builtin_variables.py, eliminating spurious[variable] INFO Can't find variable β¦log lines. Added:$http3(ngx_http_v3_module, #110),$proxy_protocol_addrand$realip_remote_addr(previously their doc comments were present but the keys were missing),$proxy_protocol_server_addr,$proxy_protocol_server_port,$proxy_protocol_tlv_*(PROXY protocol v2),$sent_trailer_*,$upstream_trailer_*,$connection_time,$request_port,$is_request_port,$limit_conn_status,$limit_req_status. List derived by diffing everyngx_(http|stream)_variable_tarray in nginx 1.29.5 source against the existing builtin table, excluding entries flaggedNGX_HTTP_VAR_NOHASH(internal-only, unreachable from configs).
v0.2.43
Added
- New check:
ssl_stapling_without_resolverβ flags SSL servers wheressl_stapling onis in effect but noresolverdirective is reachable in scope. Without a resolver nginx can't fetch the OCSP response and stapling silently fails; clients fall back to making their own OCSP queries, adding handshake latency and defeating the point of stapling. The check skips non-SSL servers, servers that override withssl_stapling off, and any configuration where aresolveris visible in the server or an enclosing scope. nginx_cvesdatabase expansion β the CVE advisor now ships every nginx Open Source CVE listed on nginx.org/en/security_advisories.html. 50 entries spanning 2009 through 2026, up from a single entry in v0.2.42. Config-pattern triggers cover the mp4, HTTP/2, HTTP/3/QUIC, resolver, SSL session reuse, dav, scgi/uwsgi, charset, mail, stream-OCSP, SPDY, and SSL/TLS directives; pure binary-level bugs (CVE-2013-2028 chunked parser, CVE-2009-2629 URI buffer underflow, ...) fire from the version match alone. Range subtraction at module load time removes per-branch post-fix tails β users on patched stable branches (1.26.3vs CVE-2025-23419,1.22.1vs CVE-2022-41741,1.16.1vs CVE-2019-9511, ...) are no longer flagged for CVEs their version actually patches.
Changed
nginx_cvesgating semantics β a CVE with a config-pattern trigger now fires only when the trigger directive is present. The previous version-only fallback was noisy at scale; mp4-module CVEs no longer flag configs that never load mp4. Pure binary-level CVEs (no trigger) continue to fire whenever the version matches.
Fixed
- Variable scope tracking β recognize
set-like directives (set,auth_request_set,perl_set,set_by_lua,root) across block scopes regardless of source order. Variables defined later in aserver {}(or any parent) block are now visible to nestedlocation {}blocks that reference them, matching nginx's parse-time variable registration. Eliminates falseCan't find variableINFO logs (#100).
Full changelog: https://github.com/dvershinin/gixy/blob/master/CHANGELOG.md
v0.2.42
What's New
Added β nginx_cves: unified nginx CVE advisor
Pass --nginx-version=X.Y.Z and gixy will report every CVE whose affected range covers your installed version, with the upgrade target. CVEs that also have a config-trigger pattern (currently CVE-2026-42945) enrich the report with the offending directives, so you see both "your binary is vulnerable" and "your config triggers it here" at once.
Without --nginx-version, the check stays silent β gixy is config-static and has no view of the binary, so there is nothing safe to assert.
$ gixy --nginx-version=1.29.8 /etc/nginx/nginx.conf
[HIGH] Known nginx CVE affects your installed version.
CVE-2026-42945 ("NGINX Rift"): Heap overflow in ngx_http_rewrite_module.
Your installed version is vulnerable AND the trigger pattern is present
in this config. Fixed in: 1.30.1, 1.31.0 (Plus: R32 P6, R36 P4).
First database entry: CVE-2026-42945 ("NGINX Rift")
- Severity: HIGH (CVSS 9.2)
- Affected: nginx OSS
0.6.27..1.30.0; nginx PlusR32..R36 - Fixed in:
1.30.1,1.31.0; PlusR32 P6,R36 P4 - Trigger pattern: a
rewritewhose replacement contains both an unnamed PCRE backreference ($1..$9or${1}..${9}) and a literal?, followed by anotherrewrite/if/setin the same parent context. The script engine compiles an under-sized destination buffer using one escaping method, then writes viaNGX_ESCAPE_ARGSin a second pass β the difference overflows the heap. - Mitigation: switch to named captures (
(?<name>...)referenced as${name}), or upgrade. - Advisory: NVD CVE-2026-42945
Extending the database
Adding a future CVE is one append to _CVES in gixy/plugins/nginx_cves.py; if it has a config-pattern trigger, drop a small _check_cve_<id>(root) generator alongside it.
Tests
Includes a regression fixture (tests/integration/inline_return_with_map.conf) pinning the fix for #105 β variable resolution in multiline return directive bodies referencing variables defined by map blocks.
Install / upgrade: pip install -U gixy-ng Β· Docker: docker pull getpagespeed/gixy:v0.2.42
v0.2.41
What's New
New check: regex_exact_match
Detects regex locations like location ~ ^/path$ that match a single literal path and can be replaced with an exact-match location (location = /path) for better performance.
NGINX processes exact-match locations first and skips the regex engine entirely, making them significantly faster.
Before:
location ~ ^/api/health$ {
return 200;
}After:
location = /api/health {
return 200;
}Includes quick-fix support for IDE integrations. Only flags case-sensitive regex (~), not case-insensitive (~*), since = is always case-sensitive.