CVE-2026-61629
nginx ignition has ParseAcceptLanguage `_` separator bypass that enables ~75x CPU amplification via Accept-Language header in i18nMiddleware
nginx ignition is a user interface for the nginx web server. In versions 2.29.0 through 2.40.0, the gin i18n middleware in nginx-ignition's API server runs in front of every HTTP request and calls golang.org/x/text/language.ParseAcceptLanguage on the raw Accept-Language header without imposing any size or shape filter. The underlying parser has quadratic-time behaviour on long lists of malformed language tags. The CVE-2022-32149 guard that golang.org/x/text added in v0.3.8 caps the number of - characters in the input at 1000, but it does not cap _ characters even though the parser's internal scanner aliases _ to - before parsing. A single unauthenticated GET request with an Accept-Language header built out of _ separators burns about 2.4 seconds of server CPU on the host running nginx-ignition; ten concurrent attackers saturate a ten-core box for the duration of the attack while consuming ~10 MiB/s of upstream bandwidth. Version 2.40.1 fixes this issue.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- None
- Integrity
- None
- Availability
- High
Exploit likelihood
What each source reports
CVE List Score used
7.5
nginx ignition has ParseAcceptLanguage `_` separator bypass that enables ~75x CPU amplification via Accept-Language header in i18nMiddleware
nginx ignition is a user interface for the nginx web server. In versions 2.29.0 through 2.40.0, the gin i18n middleware in nginx-ignition's API server runs in front of every HTTP request and calls golang.org/x/text/language.ParseAcceptLanguage on the raw Accept-Language header without imposing any size or shape filter. The underlying parser has quadratic-time behaviour on long lists of malformed language tags. The CVE-2022-32149 guard that golang.org/x/text added in v0.3.8 caps the number of - characters in the input at 1000, but it does not cap _ characters even though the parser's internal scanner aliases _ to - before parsing. A single unauthenticated GET request with an Accept-Language header built out of _ separators burns about 2.4 seconds of server CPU on the host running nginx-ignition; ten concurrent attackers saturate a ten-core box for the duration of the attack while consuming ~10 MiB/s of upstream bandwidth. Version 2.40.1 fixes this issue.
- Record
CVE-2026-61629- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-770
- Updated
- 2026-11-02
EUVDEUVD-2026-83924
7.5
nginx ignition is a user interface for the nginx web server. In versions 2.29.0 through 2.40.0, the gin i18n middleware in nginx-ignition's API server runs in front of every HTTP request and calls golang.org/x/text/language.ParseAcceptLanguage on the raw Accept-Language header without imposing any size or shape filter. The underlying parser has quadratic-time behaviour on long lists of malformed language tags. The CVE-2022-32149 guard that golang.org/x/text added in v0.3.8 caps the number of - characters in the input at 1000, but it does not cap _ characters even though the parser's internal scanner aliases _ to - before parsing. A single unauthenticated GET request with an Accept-Language header built out of _ separators burns about 2.4 seconds of server CPU on the host running nginx-ignition; ten concurrent attackers saturate a ten-core box for the duration of the attack while consuming ~10 MiB/s of upstream bandwidth. Version 2.40.1 fixes this issue.
- Record
EUVD-2026-83924- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-jr34-h97m-9hpx
7.5
nginx ignition has ParseAcceptLanguage `_` separator bypass that enables ~75x CPU amplification via Accept-Language header in i18nMiddleware
Summary
The gin i18n middleware in nginx-ignition's API server runs in front of every HTTP request and calls golang.org/x/text/language.ParseAcceptLanguage on the raw Accept-Language header without imposing any size or shape filter. The underlying parser has quadratic-time behaviour on long lists of malformed language tags. The CVE-2022-32149 guard that golang.org/x/text added in v0.3.8 caps the number of - characters in the input at 1000, but it does not cap _ characters even though the parser's internal scanner aliases _ to - before parsing. A single unauthenticated GET request with an Accept-Language header built out of _ separators burns about 2.4 seconds of server CPU on the host running nginx-ignition; ten concurrent attackers saturate a ten-core box for the duration of the attack while consuming ~10 MiB/s of upstream bandwidth.
Affected versions
dillmann.com.br/nginx-ignition v2.40.0 and (per code inspection of main) earlier 2.x versions whose api/common/server/i18n.go middleware routes the Accept-Language header through language.ParseAcceptLanguage without imposing its own size or character filter. Verified on:
- the official
dillmann/nginx-ignition:latestDocker image at v2.40.0 (E2E below) mainat commitfaef4c99442b329cfa4ee8879bdba41c22866a18by readingapi/common/server/i18n.go(the middleware is unchanged)
Privilege required
Unauthenticated. The middleware is registered on the global gin router that serves both the login page and the unauthenticated /api/health style endpoints. Anyone who can reach the HTTP listener (port 8090 by default) is in scope.
Vulnerable code
api/common/server/i18n.go (blob SHA faef4c99442b329cfa4ee8879bdba41c22866a18):
func i18nMiddleware(commands i18n.Commands) gin.HandlerFunc {
return func(ginCtx *gin.Context) {
lang := commands.DefaultLanguage()
langHeader := ginCtx.GetHeader("Accept-Language")
tags, _, err := language.ParseAcceptLanguage(langHeader)
if err == nil && len(tags) > 0 {
for _, tag := range tags {
if commands.Supports(tag) {
lang = tag
break
}
}
}
//nolint:staticcheck
updatedCtx := context.WithValue(ginCtx.Request.Context(), i18n.ContextKey, lang)
ginCtx.Request = ginCtx.Request.WithContext(updatedCtx)
ginCtx.Set(i18n.ContextKey, lang)
ginCtx.Next()
}
}
ginCtx.GetHeader("Accept-Language") is the unfiltered HTTP header. Go's default net/http MaxHeaderBytes is 1 << 20 = 1 MiB and nginx-ignition does not override it, so the parser is allowed to receive up to a megabyte of attacker-controlled data.
CVE-2022-32149 hardened ParseAcceptLanguage by counting - characters and rejecting inputs with more than 1000 of them. The guard does not count _ characters even though the scanner converts _ to - at parse time (golang.org/x/text/internal/language/parse.go). A 1 MiB header full of 9-character _abcdefghi tokens contains zero - characters, passes the guard, and then drives the scanner into the O(N²) gobble path.
How Accept-Language reaches ParseAcceptLanguage
Every HTTP request that hits the nginx-ignition API server passes through i18nMiddleware (registered as a global gin middleware). The middleware sequence is:
- The request enters
i18nMiddleware. ginCtx.GetHeader("Accept-Language")returns the full attacker-supplied header value.language.ParseAcceptLanguage(langHeader)runs unfiltered.
No size or character-class filter is applied between (2) and (3). The middleware runs for every gin handler, including unauthenticated paths like the root URL and /api/health (which…
- Record
GHSA-jr34-h97m-9hpx- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-770
- Updated
- 2026-11-02
NVD
7.5
nginx ignition is a user interface for the nginx web server. In versions 2.29.0 through 2.40.0, the gin i18n middleware in nginx-ignition's API server runs in front of every HTTP request and calls golang.org/x/text/language.ParseAcceptLanguage on the raw Accept-Language header without imposing any size or shape filter. The underlying parser has quadratic-time behaviour on long lists of malformed language tags. The CVE-2022-32149 guard that golang.org/x/text added in v0.3.8 caps the number of - characters in the input at 1000, but it does not cap _ characters even though the parser's internal scanner aliases _ to - before parsing. A single unauthenticated GET request with an Accept-Language header built out of _ separators burns about 2.4 seconds of server CPU on the host running nginx-ignition; ten concurrent attackers saturate a ten-core box for the duration of the attack while consuming ~10 MiB/s of upstream bandwidth. Version 2.40.1 fixes this issue.
- Record
CVE-2026-61629- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-770
- Updated
- 2026-11-02
OSV
7.5
nginx ignition has ParseAcceptLanguage `_` separator bypass that enables ~75x CPU amplification via Accept-Language header in i18nMiddleware
nginx ignition is a user interface for the nginx web server. In versions 2.29.0 through 2.40.0, the gin i18n middleware in nginx-ignition's API server runs in front of every HTTP request and calls golang.org/x/text/language.ParseAcceptLanguage on the raw Accept-Language header without imposing any size or shape filter. The underlying parser has quadratic-time behaviour on long lists of malformed language tags. The CVE-2022-32149 guard that golang.org/x/text added in v0.3.8 caps the number of - characters in the input at 1000, but it does not cap _ characters even though the parser's internal scanner aliases _ to - before parsing. A single unauthenticated GET request with an Accept-Language header built out of _ separators burns about 2.4 seconds of server CPU on the host running nginx-ignition; ten concurrent attackers saturate a ten-core box for the duration of the attack while consuming ~10 MiB/s of upstream bandwidth. Version 2.40.1 fixes this issue.
- Record
CVE-2026-61629- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-770
- Updated
- 2026-11-02
OSVGHSA-jr34-h97m-9hpx
7.5
nginx ignition has ParseAcceptLanguage `_` separator bypass that enables ~75x CPU amplification via Accept-Language header in i18nMiddleware
Summary
The gin i18n middleware in nginx-ignition's API server runs in front of every HTTP request and calls golang.org/x/text/language.ParseAcceptLanguage on the raw Accept-Language header without imposing any size or shape filter. The underlying parser has quadratic-time behaviour on long lists of malformed language tags. The CVE-2022-32149 guard that golang.org/x/text added in v0.3.8 caps the number of - characters in the input at 1000, but it does not cap _ characters even though the parser's internal scanner aliases _ to - before parsing. A single unauthenticated GET request with an Accept-Language header built out of _ separators burns about 2.4 seconds of server CPU on the host running nginx-ignition; ten concurrent attackers saturate a ten-core box for the duration of the attack while consuming ~10 MiB/s of upstream bandwidth.
Affected versions
dillmann.com.br/nginx-ignition v2.40.0 and (per code inspection of main) earlier 2.x versions whose api/common/server/i18n.go middleware routes the Accept-Language header through language.ParseAcceptLanguage without imposing its own size or character filter. Verified on:
- the official
dillmann/nginx-ignition:latestDocker image at v2.40.0 (E2E below) mainat commitfaef4c99442b329cfa4ee8879bdba41c22866a18by readingapi/common/server/i18n.go(the middleware is unchanged)
Privilege required
Unauthenticated. The middleware is registered on the global gin router that serves both the login page and the unauthenticated /api/health style endpoints. Anyone who can reach the HTTP listener (port 8090 by default) is in scope.
Vulnerable code
api/common/server/i18n.go (blob SHA faef4c99442b329cfa4ee8879bdba41c22866a18):
func i18nMiddleware(commands i18n.Commands) gin.HandlerFunc {
return func(ginCtx *gin.Context) {
lang := commands.DefaultLanguage()
langHeader := ginCtx.GetHeader("Accept-Language")
tags, _, err := language.ParseAcceptLanguage(langHeader)
if err == nil && len(tags) > 0 {
for _, tag := range tags {
if commands.Supports(tag) {
lang = tag
break
}
}
}
//nolint:staticcheck
updatedCtx := context.WithValue(ginCtx.Request.Context(), i18n.ContextKey, lang)
ginCtx.Request = ginCtx.Request.WithContext(updatedCtx)
ginCtx.Set(i18n.ContextKey, lang)
ginCtx.Next()
}
}
ginCtx.GetHeader("Accept-Language") is the unfiltered HTTP header. Go's default net/http MaxHeaderBytes is 1 << 20 = 1 MiB and nginx-ignition does not override it, so the parser is allowed to receive up to a megabyte of attacker-controlled data.
CVE-2022-32149 hardened ParseAcceptLanguage by counting - characters and rejecting inputs with more than 1000 of them. The guard does not count _ characters even though the scanner converts _ to - at parse time (golang.org/x/text/internal/language/parse.go). A 1 MiB header full of 9-character _abcdefghi tokens contains zero - characters, passes the guard, and then drives the scanner into the O(N²) gobble path.
How Accept-Language reaches ParseAcceptLanguage
Every HTTP request that hits the nginx-ignition API server passes through i18nMiddleware (registered as a global gin middleware). The middleware sequence is:
- The request enters
i18nMiddleware. ginCtx.GetHeader("Accept-Language")returns the full attacker-supplied header value.language.ParseAcceptLanguage(langHeader)runs unfiltered.
No size or character-class filter is applied between (2) and (3). The middleware runs for every gin handler, including unauthenticated paths like the root URL and /api/health (which…
- Record
GHSA-jr34-h97m-9hpx- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Weakness
- CWE-770
- Updated
- 2026-11-02
OSVUBUNTU-CVE-2026-61629
7.5
nginx ignition is a user interface for the nginx web server. In versions 2.29.0 through 2.40.0, the gin i18n middleware in nginx-ignition's API server runs in front of every HTTP request and calls golang.org/x/text/language.ParseAcceptLanguage on the raw Accept-Language header without imposing any size or shape filter. The underlying parser has quadratic-time behaviour on long lists of malformed language tags. The CVE-2022-32149 guard that golang.org/x/text added in v0.3.8 caps the number of - characters in the input at 1000, but it does not cap _ characters even though the parser's internal scanner aliases _ to - before parsing. A single unauthenticated GET request with an Accept-Language header built out of _ separators burns about 2.4 seconds of server CPU on the host running nginx-ignition; ten concurrent attackers saturate a ten-core box for the duration of the attack while consuming ~10 MiB/s of upstream bandwidth. Version 2.40.1 fixes this issue.
- Record
UBUNTU-CVE-2026-61629- CVSS 3.1
- 7.5 High
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H - Updated
- 2026-11-02
OSVGO-2026-6539 No score
nginx ignition has ParseAcceptLanguage `_` separator bypass that enables ~75x CPU amplification via Accept-Language header in i18nMiddleware in github.com/lucasdillmann/nginx-ignition
nginx ignition has ParseAcceptLanguage _ separator bypass that enables ~75x CPU amplification via Accept-Language header in i18nMiddleware in github.com/lucasdillmann/nginx-ignition
- Record
GO-2026-6539- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
github.com/lucasdillmann/nginx-ignitionGo |
0.0.0-20260126024607-cbaf0fc16ed8 up to 0.0.0-20260526022344-0c988fc1277c | 0.0.0-20260526022344-0c988fc1277c |
History
| Recorded | Changed | Sources |
|---|---|---|
| affected | ||
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-61629 is a high vulnerability (CVSS 7.5) in Lucasdillmann Nginx-ignition, published September 21, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.42%, the 36th percentile. Fixed in github.com/lucasdillmann/nginx-ignition 0.0.0-20260526022344-0c988fc1277c.
References
github.com/lucasdillmann/nginx-ignition/security/advisories/GHSA-jr34-h97m-9hpx
github.com/lucasdillmann/nginx-ignition/commit/0c988fc1277c7d291725e8373313f8486fa1b31a
github.com/lucasdillmann/nginx-ignition/commit/cbaf0fc16ed873f7178a2ca9b0d00a696e44b485
nvd.nist.gov/vuln/detail/CVE-2026-61629
github.com/lucasdillmann/nginx-ignition/pull/125
github.com/lucasdillmann/nginx-ignition/releases/tag/2.40.1
Left out here: the rest of 2 source descriptions. The JSON record has them.