Update docker.io/gotenberg/gotenberg Docker tag to v9 #186

Open
renovate wants to merge 1 commit from renovate/docker.io-gotenberg-gotenberg-9.x into main
Member

This PR contains the following updates:

Package Update Change
docker.io/gotenberg/gotenberg major 8.38.1 → 9.0.0

Release Notes

gotenberg/gotenberg (docker.io/gotenberg/gotenberg)

v9.0.0: 9.0.0

Compare Source

Gotenberg 9 is out 🎉

[!IMPORTANT]
latest now points to Gotenberg 9. Pin gotenberg/gotenberg:8 until you have upgraded. The upgrade guide maps every Gotenberg 8 route, field, flag, metric and span to its Gotenberg 9 counterpart.

One PDF engine

pdfcpu, QPDF, pdftk and ExifTool are replaced by litho, a PDF engine written in Go for Gotenberg, running in-process.

remediate repairs a PDF until it conforms to one of the eleven PDF/A levels, to PDF/UA-1 or PDF/UA-2, to both together, or to Factur-X, then checks its own result: Gotenberg-Remediation-Residual counts the violations left, Gotenberg-Remediation-Rolled-Back the fixes undone to keep pages, text and images. /forms/pdf/validate runs the same checks on any PDF.

litho also signs and timestamps, redacts from the file rather than from view, infers a structure tree, renders pages as images, fills and flattens forms in the scripts the image's fonts cover, and shrinks a PDF without touching image quality. A stage that would drop the signatures of a signed PDF answers 400, as does text no font can draw.

Stages, in your order

Post-processing is no longer flat fields in a fixed order. A stages list runs as written, on every route that makes a PDF and on /forms/pdf/pipe for PDFs you already have:

[{"op": "merge"}, {"op": "stamp-text", "text": "DRAFT"}, {"op": "remediate", "profile": "PDF/A-2b"}]

26 stages, each also a /forms/pdf/<op> route with form fields, plus six JSON read routes: info, validation, metadata, bookmarks, attachments and form fields. A broken order answers 400 before anything runs.

LibreOffice through lok

unoconverter, Python and the soffice listener are replaced by lok, a long-running LibreOfficeKit process that Gotenberg supervises and restarts after a crash. Macros stay off; --libreoffice-enable-macros runs them.

Fewer dependencies, less CVE surface

Java, Python, unoconverter, pdfcpu, QPDF, pdftk and ExifTool leave the image: fewer packages to patch, and no more CVE reports about tools Gotenberg does not ship. Variants, architectures, user, port and command don't change.

Upgrading

Start from the upgrade guide. /forms/pdfengines routes become /forms/pdf routes, post-processing fields become stages, and a field with a stage twin now starts with native. A removed route answers 404 naming its replacement, a Gotenberg 8 field 400 saying where it went:

Invalid form data: form field 'merge' is unknown to this route; Gotenberg 9 moved it to a stage: add {"op":"merge"} to 'stages'

Custom builds import github.com/gotenberg/gotenberg/v9. The PdfEngine, PdfEngineProvider and MetricsProvider interfaces and the Prometheus module are gone: OTEL_METRICS_EXPORTER=prometheus serves the same.

Everything else

PDF
  • set-form selects several list items, refuses a value a field cannot hold, and lists the PDF's fields when you name a missing one. flatten-form draws a value without appearance over the field's own background and border.
  • Flattened values and text stamps beyond Western European text use an installed font, embedded and subset. Uncovered text answers 400 naming the characters.
  • optimize packs objects into compressed streams, stores identical streams once, recompresses images losslessly and subsets fonts. Every pass runs unless turned off. An encrypted input needs a decrypt or encrypt stage first.
  • merge keeps each file's bookmarks, remapped, and names the result after the first file in alphanumeric order.
  • render draws pages as PNG or JPEG at the resolution you ask.
  • --pdf-max-stream-bytes, --pdf-max-embedded-file-bytes and --pdf-max-image-pixels bound what litho reads. --pdf-allow-list, --pdf-deny-list and their siblings filter the timestamp authorities it calls.
LibreOffice
  • nativePdfa takes PDF/A-1b, PDF/A-2b, PDF/A-3b or PDF/A-4; nativePdfua takes PDF/UA-1. The PDF/A export is no longer redone after the other steps: end the stages with remediate when they may break conformance.
  • initialView, magnification and pageLayout take names such as outline or fitWidth, not numbers. firstPageOnLeft, which LibreOffice ignored, and nativePdfFormats are gone.
  • nativeWatermarkColor takes #rrggbb, nativeWatermarkRotation degrees counter-clockwise, 0 being horizontal. A plain and a tiled watermark together answer 400.
  • CSV files split into columns. .epub is no longer accepted.
  • PDFs are named after their documents, report.docx.pdf, even for a single one. Gotenberg-Output-Filename still overrides.
Chromium
  • paperSize names a format, for LibreOffice too: A3, A4, A5, B4, B5, Letter, Legal or Tabloid.
  • waitForWindowStatus, renamed from waitWindowStatus, now waits as documented. skipNetworkAlmostIdleEvent=false now really waits for networkAlmostIdle.
  • The page sent to the HTML and Markdown routes passes the allow and deny lists, which keep governing what it loads.
  • Print settings Chromium rejects answer 400: a scale out of range, a negative length, a waitDelay longer than the API timeout. A wait that outlasts the request answers 503 naming the field and its value.
  • failOnHttpStatusCodes judges the main page by its frame, not its URL. Screenshot quality goes from 1 to 100.
  • DevTools messages leave the debug logs unless --chromium-debug-protocol is set. URL queries and extra header values stay out too.
API
  • archives unpacks uploaded ZIPs, bounded by --api-archive-max-entries and --api-archive-max-ratio.
  • Errors say what to send: the value sent and the one wanted, a stage option's expected value instead of a Go type, the host that does not resolve. NaN and infinities are refused.
  • Webhook and downloadFrom URLs must be absolute http or https URLs with a host. Gotenberg-Webhook-Events-Url is required with Gotenberg-Webhook-Url and receives errors as webhook.error events: the error URL, method and lists are gone. A failed upload says what the webhook answered, or why it was unreachable.
  • A non-ASCII Gotenberg-Output-Filename is encoded per RFC 6266. Every answer carries the trace header, 404 and 405 included; the version header too, without authentication.
  • The banner is an aligned startup summary, one log record outside a terminal. --api-bind-ip takes IPv6, --api-start-timeout bounds module readiness, /debug reports the lok and litho versions.
  • Debug logs mask form values, extra header values and document passwords.
Telemetry
  • Names follow the OpenTelemetry rules: gotenberg.chromium.requests, gotenberg.<engine>.queue.size, chromium.pdf, webhook.send. A failed request carries error.type; the status attribute and the errors counter are gone.
  • Each webhook and download attempt is an HTTP client span under the whole call's span, with server.address and a url.full stripped of credentials, query and fragment. Outbound URLs lose their query in errors and logs too.
  • The server span stays unset on success and 4xx, and sets Error on 5xx with the status code as error.type. OTEL_PROPAGATORS selects the propagators. Each written document is traced, its editing stages as child spans.
Security
  • The 8.40.0 fixes are in: IANA non-globally-reachable ranges are private for the *_DENY_PRIVATE_IPS checks, Chromium distrusts the compromised eMudhra roots from the first request, and the pinning proxy stays on with --chromium-host-resolver-rules.
  • Pinning proxy tunnels are bound to the server that accepted them. Refused outbound requests are logged with their context, redacted URL and rule.
  • Engine temporary files are collected by exact pattern, Chromium's profile directory is removed after a failed start, and handler panics answer 500 at once.
Removed
  • The deprecated --log-format, --log-enable-gcp-fields, --api-trace-header, --api-disable-health-check-logging, --chromium-incognito, --webhook-error-allow-list and --webhook-error-deny-list flags, and the --pdfengines-* and --prometheus-* ones.
  • UNOCONVERTER_BIN_PATH, replaced by LOK_BIN_PATH, and the pdfcpu, QPDF, pdftk and ExifTool paths.
  • downloadFrom[].embedded, facturxVersion and the merge bookmark options: the guide names their replacements.

Chore

  • Debian 13, Chromium 156 (146 on ppc64le), LibreOffice 26.8 from Debian's backports, Go 1.27, lok v0.0.6, litho v0.0.7.
  • CI runs the integration suite on every push to main and tests the Chromium and LibreOffice variants.
  • The Bruno collection mirrors every route.

v8.40.0: 8.40.0

Compare Source

[!IMPORTANT]
8.40.0 is the final release of Gotenberg 8. The next release is Gotenberg 9.

Security Fixes ⚠️

  • Pass the encryption passwords to QPDF as option values. QPDF received userPassword and ownerPassword as positional arguments, and it reads an argument that starts with @ as a file of further arguments. A password of @/proc/self/cmdline, with newlines in the other one, injected options such as --add-attachment, and the returned PDF embedded any file the gotenberg user can read. QPDF now receives --user-password= and --owner-password=, and every password encrypts the PDF as typed.
  • Treat every special-purpose address range as non-public. The *_DENY_PRIVATE_IPS checks let through ranges that IANA marks as not globally reachable, such as the IPv6 benchmarking range 2001:2::/48, while they refused its IPv4 twin 198.18.0.0/15. They now refuse every such block: 0.0.0.0/8, where Docker Desktop answers its host gateway, 192.0.0.0/24, the documentation ranges, 192.88.99.0/24 and 240.0.0.0/4 in IPv4, and the whole 2001::/23 block, 3fff::/20, 5f00::/16 and 100:0:0:1::/64 in IPv6.
  • Distrust the compromised eMudhra roots in Chromium from the first request. 8.39.0 removed them from the OS bundle and the Java trust store, but Chromium's root store still trusted emSign ECC Root CA - G3 until its component updater fetched a CRLSet, about two minutes after each start, and never without access to Google's update servers. Every Chromium restart opened the window again. A managed policy now distrusts emSign ECC Root CA - G3, emSign Root TLS CA - G3 and AAA Certificate Services at startup.
  • Keep the pinning proxy on with --chromium-host-resolver-rules. Any host-resolver rule turned the pinning proxy off, and with it the only layer that refuses a WebSocket handshake: with --chromium-deny-private-ips set, a page, or a Web Worker, could open a WebSocket to a private address, and Gotenberg only logged it. Gotenberg now applies the rules itself, with Chromium's MAP and EXCLUDE semantics, in its outbound checks and in the proxy, so the IP-class checks judge the address a rule maps a host to.

Behavior Changes

  • An invalid --chromium-host-resolver-rules stops Gotenberg at startup. Chromium skipped a rule it could not parse, so a typo silently sent requests elsewhere.
  • Gotenberg, not Chromium, applies the host-resolver rules. Loopback requests now go through the pinning proxy when a rule is set, and a host that only a MAP rule knows works as the URL to print, where it returned 403 before. Hops carried by the environment proxy keep their original host.
  • --chromium-proxy-server with an outbound policy logs a warning at startup. WebSocket handshakes reach that proxy without Gotenberg's checks, so enforce the policy there.
  • The *_DENY_PRIVATE_IPS checks refuse more ranges. See the security fix above. The rule covers whole blocks, so a few anycast services inside 192.0.0.0/24 and 2001::/23 are refused too.
  • The linux/386 image needs seccomp=unconfined on Docker 29.4 and later. Docker's default seccomp profile now denies socketcall on i386, to block the AF_ALG sockets of CVE-2026-31431, and Gotenberg opens its sockets through it on that architecture. The container fails to start with listen tcp :3000: socket: function not implemented. Run it with --security-opt seccomp=unconfined, or with a copy of Docker's default profile that allows socketcall, and keep the host kernel patched. This comes from Docker and affects earlier releases too.

Bug Fixes

  • LibreOffice stopped answering after a restart (#​1713). Since 8.32.0, the socket port was picked before LibreOffice's outbound proxy started, so the kernel could hand that same port to the proxy. LibreOffice then ran without its socket, the health check reached the proxy and reported it healthy, and every LibreOffice request timed out until the container restarted. The port is now picked once the proxy listens, and the startup and health checks wait for LibreOffice's own UNO greeting. Thanks @​chladic.
  • Merging with pdfa on /forms/libreoffice/convert returned a PDF that was not PDF/A (#​1705). Each document got the formats before the merge, which undid them. The formats now apply once, to the merged file, as on /forms/pdfengines/merge. Thanks @​APX403.
  • Chromium called Google services at every start (#​1706). Optimization hints, network time queries and account checks reached Google, or logged blocked CONNECTs in locked-down deployments. Those features are now off, and the sign-in URL points to a closed loopback port. Thanks @​Moufle.
  • Aberrant print settings returned 500 (#​1707). Only an empty content area returned 400. A scale outside 0.1 to 2, a negative margin, a zero paper size and every other print parameter Chromium rejects now return 400 too. Thanks @​SergeevDmitry.
  • optimizeImages swapped images between the pages of a merged PDF (#​1708). Two merged documents may give their images the same name, such as X5. Extracted images are now matched by page and name. Thanks @​APX403.
  • optimizeImages made charts larger (#​1714). Charts and other flat-color images often take more space as JPEG than in their lossless stream. A replacement is now kept only when it makes the file smaller, so the pass never grows a PDF. Thanks @​APX403.

Chore

  • Updated Chromium to 156.0.8078.79.
  • Updated LibreOffice to 26.8.2.
  • Dropped python3-distutils-extra, and the 45 unused packages it pulled in, from the images that ship LibreOffice (#​1711, #​1710). Thanks @​yusufgngor.
  • Pinned golangci-lint v2.15.0 in the Makefile, so local and CI linting match.
  • Updated Go dependencies.

v8.39.0: 8.39.0

Compare Source

Security Fixes ⚠️

  • Reject ExifTool's j option alias and stop loading ExifTool config files. The metadata check blocked json but not its alias j. A metadata key could import a JSON file carrying a HardLink pseudo-tag, plant ~/.ExifTool_config, and have the next ExifTool run execute it as Perl. The keys j, addtagsfromfile, and alltagsfromfile now return 400, and Gotenberg always runs ExifTool with -config "".
  • Accept only http:// and https:// URLs on the URL routes. The default deny-list only covered file://, so devtools://devtools/bundled/devtools_app.html loaded Chromium's privileged DevTools page, and waitForExpression ran there with access to local files. /forms/chromium/convert/url and /forms/chromium/screenshot/url now return 400 for any other scheme.
  • Apply path and wss:// deny rules to WebSocket handshakes. The pinning proxy matched CONNECT tunnels against https://host:port, so a deny rule anchored on a path, such as ^https?://host/, or on wss:// refused the plain request but let the handshake through. The proxy now matches tunnels against each scheme's root URL, and a handshake whose full URL is denied fails the conversion with a generic 403.
  • Drop the compromised eMudhra roots (#​1699). The images trusted emSign ECC Root CA - G3 and AAA Certificate Services, whose intermediates have recoverable private keys. The OS bundle now comes from ca-certificates 20250419+deb13u1, and the Java trust store used by PDFtk drops both roots. Correction: Chromium 156 still accepted these chains for about two minutes after each start, until its component updater fetched a CRLSet, and never without access to Google's update servers. The next release, 8.40.0, distrusts both roots in Chromium from the first request. Thanks @​hrueger.

New Features

  • failOnConsoleMessageTypes for Chromium (#​1667). Fails the conversion with 409 when the page logs a console message of one of the given types (log, debug, info, warning, error, assert). The response lists the messages. Thanks @​jschneider.
  • PDF/A-4 (#​1703). The pdfa form field now accepts PDF/A-4 on every route that supports it, through the LibreOffice PDF engine. Thanks @​henningda.
  • Gotenberg-Version response header (#​1693). Set on every authenticated route, error responses included, and on webhook deliveries. It is not set on 401 responses or /health (#​1694). Thanks @​fragkakis.

Behavior Changes

  • The URL routes reject non-HTTP schemes. chrome://, devtools://, data:, and any other scheme besides http and https now return 400.
  • ExifTool ignores ~/.ExifTool_config. The metadata keys j, addtagsfromfile, and alltagsfromfile now return 400. Prefix them with a group, for example XMP:j, to write a tag of that name.
  • The XRECHNUNG Factur-X profile embeds xrechnung.xml. See the bug fix below.

Bug Fixes

  • Sporadic 502 on uploads behind HTTP/2 proxies (#​1112). Behind Cloud Run with an h2c port, the proxy sent large DATA frames, Go answered with a flood of WINDOW_UPDATE frames, and the proxy dropped the connection mid-upload. Gotenberg now advertises the 16 KiB HTTP/2 default frame size (#​1700). Thanks @​TessilimiTheo and @​geoherna.
  • No listener with absolute TLS paths (#​1690). Since 8.38.0, --api-tls-cert-file and --api-tls-key-file with absolute paths left Gotenberg running without accepting connections. Both paths work again, and a missing or unreadable file now fails the startup (#​1691). Thanks @​n-rodriguez.
  • Empty stampSource or watermarkSource returned 400 (#​1692). Since 8.36.0, a blank source failed the merge, split, Chromium, and LibreOffice routes. An empty source is skipped again. Thanks @​APX403.
  • OIDC rejected bearer in lower case (#​1696). The Authorization scheme is now matched case-insensitively, as RFC 9110 requires. Thanks @​MaxFreedomPollard.
  • The XRECHNUNG Factur-X profile embedded factur-x.xml (#​1701). The spec requires xrechnung.xml for this profile, both as the embedded file and in fx:DocumentFileName. Other levels keep factur-x.xml. Thanks @​nhh.

Chore

  • Updated Chromium to 156.0.8078.47.
  • Updated pdfcpu to v0.16.3 and bumped Go to 1.27.3, which fix several HIGH CVEs in the Go standard library and golang.org/x modules (#​1695). Thanks @​sergeykad.
  • Updated the AWS Lambda Web Adapter to 1.1.0, which supports Lambda SnapStart (#​1704). Thanks @​michael-follmann.
  • Bumped golangci-lint to v2.15.0.
  • Updated Go dependencies.

Configuration

📅 Schedule: (UTC)

  • Branch creation
    • At any time (no schedule defined)
  • Automerge
    • At any time (no schedule defined)

🚦 Automerge: Disabled by config. Please merge this manually once you are satisfied.

♻ Rebasing: Whenever PR is behind base branch, or you tick the rebase/retry checkbox.

🔕 Ignore: Close this PR and you won't be reminded about this update again.


  • If you want to rebase/retry this PR, check this box

This PR has been generated by Mend Renovate CLI.

This PR contains the following updates: | Package | Update | Change | |---|---|---| | [docker.io/gotenberg/gotenberg](https://github.com/gotenberg/gotenberg) | major | `8.38.1` → `9.0.0` | --- ### Release Notes <details> <summary>gotenberg/gotenberg (docker.io/gotenberg/gotenberg)</summary> ### [`v9.0.0`](https://github.com/gotenberg/gotenberg/releases/tag/v9.0.0): 9.0.0 [Compare Source](https://github.com/gotenberg/gotenberg/compare/v8.40.0...v9.0.0) Gotenberg 9 is out 🎉 > \[!IMPORTANT] > `latest` now points to Gotenberg 9. Pin `gotenberg/gotenberg:8` until you have upgraded. The [upgrade guide](https://gotenberg.dev/docs/getting-started/upgrade) maps every Gotenberg 8 route, field, flag, metric and span to its Gotenberg 9 counterpart. #### One PDF engine pdfcpu, QPDF, pdftk and ExifTool are replaced by [litho](https://github.com/gotenberg/litho), a PDF engine written in Go for Gotenberg, running in-process. `remediate` repairs a PDF until it conforms to one of the eleven PDF/A levels, to PDF/UA-1 or PDF/UA-2, to both together, or to Factur-X, then checks its own result: `Gotenberg-Remediation-Residual` counts the violations left, `Gotenberg-Remediation-Rolled-Back` the fixes undone to keep pages, text and images. `/forms/pdf/validate` runs the same checks on any PDF. litho also signs and timestamps, redacts from the file rather than from view, infers a structure tree, renders pages as images, fills and flattens forms in the scripts the image's fonts cover, and shrinks a PDF without touching image quality. A stage that would drop the signatures of a signed PDF answers `400`, as does text no font can draw. #### Stages, in your order Post-processing is no longer flat fields in a fixed order. A `stages` list runs as written, on every route that makes a PDF and on `/forms/pdf/pipe` for PDFs you already have: ```json [{"op": "merge"}, {"op": "stamp-text", "text": "DRAFT"}, {"op": "remediate", "profile": "PDF/A-2b"}] ``` 26 stages, each also a `/forms/pdf/<op>` route with form fields, plus six JSON read routes: info, validation, metadata, bookmarks, attachments and form fields. A broken order answers `400` before anything runs. #### LibreOffice through lok unoconverter, Python and the `soffice` listener are replaced by [lok](https://github.com/gotenberg/lok), a long-running LibreOfficeKit process that Gotenberg supervises and restarts after a crash. Macros stay off; `--libreoffice-enable-macros` runs them. #### Fewer dependencies, less CVE surface Java, Python, unoconverter, pdfcpu, QPDF, pdftk and ExifTool leave the image: fewer packages to patch, and no more CVE reports about tools Gotenberg does not ship. Variants, architectures, user, port and command don't change. #### Upgrading Start from the [upgrade guide](https://gotenberg.dev/docs/getting-started/upgrade). `/forms/pdfengines` routes become `/forms/pdf` routes, post-processing fields become stages, and a field with a stage twin now starts with `native`. A removed route answers `404` naming its replacement, a Gotenberg 8 field `400` saying where it went: ```text Invalid form data: form field 'merge' is unknown to this route; Gotenberg 9 moved it to a stage: add {"op":"merge"} to 'stages' ``` Custom builds import `github.com/gotenberg/gotenberg/v9`. The `PdfEngine`, `PdfEngineProvider` and `MetricsProvider` interfaces and the Prometheus module are gone: `OTEL_METRICS_EXPORTER=prometheus` serves the same. #### Everything else ##### PDF - `set-form` selects several list items, refuses a value a field cannot hold, and lists the PDF's fields when you name a missing one. `flatten-form` draws a value without appearance over the field's own background and border. - Flattened values and text stamps beyond Western European text use an installed font, embedded and subset. Uncovered text answers `400` naming the characters. - `optimize` packs objects into compressed streams, stores identical streams once, recompresses images losslessly and subsets fonts. Every pass runs unless turned off. An encrypted input needs a `decrypt` or `encrypt` stage first. - `merge` keeps each file's bookmarks, remapped, and names the result after the first file in alphanumeric order. - `render` draws pages as PNG or JPEG at the resolution you ask. - `--pdf-max-stream-bytes`, `--pdf-max-embedded-file-bytes` and `--pdf-max-image-pixels` bound what litho reads. `--pdf-allow-list`, `--pdf-deny-list` and their siblings filter the timestamp authorities it calls. ##### LibreOffice - `nativePdfa` takes `PDF/A-1b`, `PDF/A-2b`, `PDF/A-3b` or `PDF/A-4`; `nativePdfua` takes `PDF/UA-1`. The PDF/A export is no longer redone after the other steps: end the stages with `remediate` when they may break conformance. - `initialView`, `magnification` and `pageLayout` take names such as `outline` or `fitWidth`, not numbers. `firstPageOnLeft`, which LibreOffice ignored, and `nativePdfFormats` are gone. - `nativeWatermarkColor` takes `#rrggbb`, `nativeWatermarkRotation` degrees counter-clockwise, `0` being horizontal. A plain and a tiled watermark together answer `400`. - CSV files split into columns. `.epub` is no longer accepted. - PDFs are named after their documents, `report.docx.pdf`, even for a single one. `Gotenberg-Output-Filename` still overrides. ##### Chromium - `paperSize` names a format, for LibreOffice too: `A3`, `A4`, `A5`, `B4`, `B5`, `Letter`, `Legal` or `Tabloid`. - `waitForWindowStatus`, renamed from `waitWindowStatus`, now waits as documented. `skipNetworkAlmostIdleEvent=false` now really waits for `networkAlmostIdle`. - The page sent to the HTML and Markdown routes passes the allow and deny lists, which keep governing what it loads. - Print settings Chromium rejects answer `400`: a `scale` out of range, a negative length, a `waitDelay` longer than the API timeout. A wait that outlasts the request answers `503` naming the field and its value. - `failOnHttpStatusCodes` judges the main page by its frame, not its URL. Screenshot `quality` goes from 1 to 100. - DevTools messages leave the debug logs unless `--chromium-debug-protocol` is set. URL queries and extra header values stay out too. ##### API - `archives` unpacks uploaded ZIPs, bounded by `--api-archive-max-entries` and `--api-archive-max-ratio`. - Errors say what to send: the value sent and the one wanted, a stage option's expected value instead of a Go type, the host that does not resolve. `NaN` and infinities are refused. - Webhook and `downloadFrom` URLs must be absolute `http` or `https` URLs with a host. `Gotenberg-Webhook-Events-Url` is required with `Gotenberg-Webhook-Url` and receives errors as `webhook.error` events: the error URL, method and lists are gone. A failed upload says what the webhook answered, or why it was unreachable. - A non-ASCII `Gotenberg-Output-Filename` is encoded per RFC 6266. Every answer carries the trace header, 404 and 405 included; the version header too, without authentication. - The banner is an aligned startup summary, one log record outside a terminal. `--api-bind-ip` takes IPv6, `--api-start-timeout` bounds module readiness, `/debug` reports the lok and litho versions. - Debug logs mask form values, extra header values and document passwords. ##### Telemetry - Names follow the OpenTelemetry rules: `gotenberg.chromium.requests`, `gotenberg.<engine>.queue.size`, `chromium.pdf`, `webhook.send`. A failed request carries `error.type`; the `status` attribute and the errors counter are gone. - Each webhook and download attempt is an HTTP client span under the whole call's span, with `server.address` and a `url.full` stripped of credentials, query and fragment. Outbound URLs lose their query in errors and logs too. - The server span stays unset on success and `4xx`, and sets Error on `5xx` with the status code as `error.type`. `OTEL_PROPAGATORS` selects the propagators. Each written document is traced, its editing stages as child spans. ##### Security - The 8.40.0 fixes are in: IANA non-globally-reachable ranges are private for the `*_DENY_PRIVATE_IPS` checks, Chromium distrusts the compromised eMudhra roots from the first request, and the pinning proxy stays on with `--chromium-host-resolver-rules`. - Pinning proxy tunnels are bound to the server that accepted them. Refused outbound requests are logged with their context, redacted URL and rule. - Engine temporary files are collected by exact pattern, Chromium's profile directory is removed after a failed start, and handler panics answer `500` at once. ##### Removed - The deprecated `--log-format`, `--log-enable-gcp-fields`, `--api-trace-header`, `--api-disable-health-check-logging`, `--chromium-incognito`, `--webhook-error-allow-list` and `--webhook-error-deny-list` flags, and the `--pdfengines-*` and `--prometheus-*` ones. - `UNOCONVERTER_BIN_PATH`, replaced by `LOK_BIN_PATH`, and the pdfcpu, QPDF, pdftk and ExifTool paths. - `downloadFrom[].embedded`, `facturxVersion` and the merge bookmark options: the guide names their replacements. #### Chore - Debian 13, Chromium 156 (146 on ppc64le), LibreOffice 26.8 from Debian's backports, Go 1.27, lok v0.0.6, litho v0.0.7. - CI runs the integration suite on every push to `main` and tests the Chromium and LibreOffice variants. - The Bruno collection mirrors every route. ### [`v8.40.0`](https://github.com/gotenberg/gotenberg/releases/tag/v8.40.0): 8.40.0 [Compare Source](https://github.com/gotenberg/gotenberg/compare/v8.39.0...v8.40.0) > \[!IMPORTANT] > 8.40.0 is the final release of Gotenberg 8. The next release is Gotenberg 9. #### Security Fixes ⚠️ - **Pass the encryption passwords to QPDF as option values.** QPDF received `userPassword` and `ownerPassword` as positional arguments, and it reads an argument that starts with `@` as a file of further arguments. A password of `@/proc/self/cmdline`, with newlines in the other one, injected options such as `--add-attachment`, and the returned PDF embedded any file the `gotenberg` user can read. QPDF now receives `--user-password=` and `--owner-password=`, and every password encrypts the PDF as typed. - **Treat every special-purpose address range as non-public.** The `*_DENY_PRIVATE_IPS` checks let through ranges that IANA marks as not globally reachable, such as the IPv6 benchmarking range `2001:2::/48`, while they refused its IPv4 twin `198.18.0.0/15`. They now refuse every such block: `0.0.0.0/8`, where Docker Desktop answers its host gateway, `192.0.0.0/24`, the documentation ranges, `192.88.99.0/24` and `240.0.0.0/4` in IPv4, and the whole `2001::/23` block, `3fff::/20`, `5f00::/16` and `100:0:0:1::/64` in IPv6. - **Distrust the compromised eMudhra roots in Chromium from the first request.** 8.39.0 removed them from the OS bundle and the Java trust store, but Chromium's root store still trusted `emSign ECC Root CA - G3` until its component updater fetched a CRLSet, about two minutes after each start, and never without access to Google's update servers. Every Chromium restart opened the window again. A managed policy now distrusts `emSign ECC Root CA - G3`, `emSign Root TLS CA - G3` and `AAA Certificate Services` at startup. - **Keep the pinning proxy on with `--chromium-host-resolver-rules`.** Any host-resolver rule turned the pinning proxy off, and with it the only layer that refuses a WebSocket handshake: with `--chromium-deny-private-ips` set, a page, or a Web Worker, could open a WebSocket to a private address, and Gotenberg only logged it. Gotenberg now applies the rules itself, with Chromium's `MAP` and `EXCLUDE` semantics, in its outbound checks and in the proxy, so the IP-class checks judge the address a rule maps a host to. #### Behavior Changes - **An invalid `--chromium-host-resolver-rules` stops Gotenberg at startup.** Chromium skipped a rule it could not parse, so a typo silently sent requests elsewhere. - **Gotenberg, not Chromium, applies the host-resolver rules.** Loopback requests now go through the pinning proxy when a rule is set, and a host that only a `MAP` rule knows works as the URL to print, where it returned `403` before. Hops carried by the environment proxy keep their original host. - **`--chromium-proxy-server` with an outbound policy logs a warning at startup.** WebSocket handshakes reach that proxy without Gotenberg's checks, so enforce the policy there. - **The `*_DENY_PRIVATE_IPS` checks refuse more ranges.** See the security fix above. The rule covers whole blocks, so a few anycast services inside `192.0.0.0/24` and `2001::/23` are refused too. - **The `linux/386` image needs `seccomp=unconfined` on Docker 29.4 and later.** Docker's default seccomp profile now denies `socketcall` on i386, to block the `AF_ALG` sockets of CVE-2026-31431, and Gotenberg opens its sockets through it on that architecture. The container fails to start with `listen tcp :3000: socket: function not implemented`. Run it with `--security-opt seccomp=unconfined`, or with a copy of Docker's default profile that allows `socketcall`, and keep the host kernel patched. This comes from Docker and affects earlier releases too. #### Bug Fixes - **LibreOffice stopped answering after a restart** ([#&#8203;1713](https://github.com/gotenberg/gotenberg/issues/1713)). Since 8.32.0, the socket port was picked before LibreOffice's outbound proxy started, so the kernel could hand that same port to the proxy. LibreOffice then ran without its socket, the health check reached the proxy and reported it healthy, and every LibreOffice request timed out until the container restarted. The port is now picked once the proxy listens, and the startup and health checks wait for LibreOffice's own UNO greeting. Thanks [@&#8203;chladic](https://github.com/chladic). - **Merging with `pdfa` on `/forms/libreoffice/convert` returned a PDF that was not PDF/A** ([#&#8203;1705](https://github.com/gotenberg/gotenberg/pull/1705)). Each document got the formats before the merge, which undid them. The formats now apply once, to the merged file, as on `/forms/pdfengines/merge`. Thanks [@&#8203;APX403](https://github.com/APX403). - **Chromium called Google services at every start** ([#&#8203;1706](https://github.com/gotenberg/gotenberg/issues/1706)). Optimization hints, network time queries and account checks reached Google, or logged blocked CONNECTs in locked-down deployments. Those features are now off, and the sign-in URL points to a closed loopback port. Thanks [@&#8203;Moufle](https://github.com/Moufle). - **Aberrant print settings returned `500`** ([#&#8203;1707](https://github.com/gotenberg/gotenberg/pull/1707)). Only an empty content area returned `400`. A `scale` outside 0.1 to 2, a negative margin, a zero paper size and every other print parameter Chromium rejects now return `400` too. Thanks [@&#8203;SergeevDmitry](https://github.com/SergeevDmitry). - **`optimizeImages` swapped images between the pages of a merged PDF** ([#&#8203;1708](https://github.com/gotenberg/gotenberg/pull/1708)). Two merged documents may give their images the same name, such as `X5`. Extracted images are now matched by page and name. Thanks [@&#8203;APX403](https://github.com/APX403). - **`optimizeImages` made charts larger** ([#&#8203;1714](https://github.com/gotenberg/gotenberg/pull/1714)). Charts and other flat-color images often take more space as JPEG than in their lossless stream. A replacement is now kept only when it makes the file smaller, so the pass never grows a PDF. Thanks [@&#8203;APX403](https://github.com/APX403). #### Chore - Updated Chromium to `156.0.8078.79`. - Updated LibreOffice to `26.8.2`. - Dropped `python3-distutils-extra`, and the 45 unused packages it pulled in, from the images that ship LibreOffice ([#&#8203;1711](https://github.com/gotenberg/gotenberg/issues/1711), [#&#8203;1710](https://github.com/gotenberg/gotenberg/pull/1710)). Thanks [@&#8203;yusufgngor](https://github.com/yusufgngor). - Pinned golangci-lint `v2.15.0` in the Makefile, so local and CI linting match. - Updated Go dependencies. ### [`v8.39.0`](https://github.com/gotenberg/gotenberg/releases/tag/v8.39.0): 8.39.0 [Compare Source](https://github.com/gotenberg/gotenberg/compare/v8.38.1...v8.39.0) #### Security Fixes ⚠️ - **Reject ExifTool's `j` option alias and stop loading ExifTool config files.** The metadata check blocked `json` but not its alias `j`. A metadata key could import a JSON file carrying a `HardLink` pseudo-tag, plant `~/.ExifTool_config`, and have the next ExifTool run execute it as Perl. The keys `j`, `addtagsfromfile`, and `alltagsfromfile` now return `400`, and Gotenberg always runs ExifTool with `-config ""`. - **Accept only `http://` and `https://` URLs on the URL routes.** The default deny-list only covered `file://`, so `devtools://devtools/bundled/devtools_app.html` loaded Chromium's privileged DevTools page, and `waitForExpression` ran there with access to local files. `/forms/chromium/convert/url` and `/forms/chromium/screenshot/url` now return `400` for any other scheme. - **Apply path and `wss://` deny rules to WebSocket handshakes.** The pinning proxy matched CONNECT tunnels against `https://host:port`, so a deny rule anchored on a path, such as `^https?://host/`, or on `wss://` refused the plain request but let the handshake through. The proxy now matches tunnels against each scheme's root URL, and a handshake whose full URL is denied fails the conversion with a generic `403`. - **Drop the compromised eMudhra roots** ([#&#8203;1699](https://github.com/gotenberg/gotenberg/issues/1699)). The images trusted `emSign ECC Root CA - G3` and `AAA Certificate Services`, whose intermediates have recoverable private keys. The OS bundle now comes from `ca-certificates` `20250419+deb13u1`, and the Java trust store used by PDFtk drops both roots. **Correction:** Chromium 156 still accepted these chains for about two minutes after each start, until its component updater fetched a CRLSet, and never without access to Google's update servers. The next release, 8.40.0, distrusts both roots in Chromium from the first request. Thanks [@&#8203;hrueger](https://github.com/hrueger). #### New Features - **`failOnConsoleMessageTypes` for Chromium** ([#&#8203;1667](https://github.com/gotenberg/gotenberg/issues/1667)). Fails the conversion with `409` when the page logs a console message of one of the given types (`log`, `debug`, `info`, `warning`, `error`, `assert`). The response lists the messages. Thanks [@&#8203;jschneider](https://github.com/jschneider). - **PDF/A-4** ([#&#8203;1703](https://github.com/gotenberg/gotenberg/pull/1703)). The `pdfa` form field now accepts `PDF/A-4` on every route that supports it, through the LibreOffice PDF engine. Thanks [@&#8203;henningda](https://github.com/henningda). - **`Gotenberg-Version` response header** ([#&#8203;1693](https://github.com/gotenberg/gotenberg/issues/1693)). Set on every authenticated route, error responses included, and on webhook deliveries. It is not set on `401` responses or `/health` ([#&#8203;1694](https://github.com/gotenberg/gotenberg/pull/1694)). Thanks [@&#8203;fragkakis](https://github.com/fragkakis). #### Behavior Changes - **The URL routes reject non-HTTP schemes.** `chrome://`, `devtools://`, `data:`, and any other scheme besides `http` and `https` now return `400`. - **ExifTool ignores `~/.ExifTool_config`.** The metadata keys `j`, `addtagsfromfile`, and `alltagsfromfile` now return `400`. Prefix them with a group, for example `XMP:j`, to write a tag of that name. - **The `XRECHNUNG` Factur-X profile embeds `xrechnung.xml`.** See the bug fix below. #### Bug Fixes - **Sporadic `502` on uploads behind HTTP/2 proxies** ([#&#8203;1112](https://github.com/gotenberg/gotenberg/issues/1112)). Behind Cloud Run with an `h2c` port, the proxy sent large DATA frames, Go answered with a flood of WINDOW_UPDATE frames, and the proxy dropped the connection mid-upload. Gotenberg now advertises the 16 KiB HTTP/2 default frame size ([#&#8203;1700](https://github.com/gotenberg/gotenberg/pull/1700)). Thanks [@&#8203;TessilimiTheo](https://github.com/TessilimiTheo) and [@&#8203;geoherna](https://github.com/geoherna). - **No listener with absolute TLS paths** ([#&#8203;1690](https://github.com/gotenberg/gotenberg/issues/1690)). Since 8.38.0, `--api-tls-cert-file` and `--api-tls-key-file` with absolute paths left Gotenberg running without accepting connections. Both paths work again, and a missing or unreadable file now fails the startup ([#&#8203;1691](https://github.com/gotenberg/gotenberg/pull/1691)). Thanks [@&#8203;n-rodriguez](https://github.com/n-rodriguez). - **Empty `stampSource` or `watermarkSource` returned `400`** ([#&#8203;1692](https://github.com/gotenberg/gotenberg/pull/1692)). Since 8.36.0, a blank source failed the merge, split, Chromium, and LibreOffice routes. An empty source is skipped again. Thanks [@&#8203;APX403](https://github.com/APX403). - **OIDC rejected `bearer` in lower case** ([#&#8203;1696](https://github.com/gotenberg/gotenberg/pull/1696)). The Authorization scheme is now matched case-insensitively, as RFC 9110 requires. Thanks [@&#8203;MaxFreedomPollard](https://github.com/MaxFreedomPollard). - **The `XRECHNUNG` Factur-X profile embedded `factur-x.xml`** ([#&#8203;1701](https://github.com/gotenberg/gotenberg/issues/1701)). The spec requires `xrechnung.xml` for this profile, both as the embedded file and in `fx:DocumentFileName`. Other levels keep `factur-x.xml`. Thanks [@&#8203;nhh](https://github.com/nhh). #### Chore - Updated Chromium to `156.0.8078.47`. - Updated pdfcpu to `v0.16.3` and bumped Go to `1.27.3`, which fix several HIGH CVEs in the Go standard library and `golang.org/x` modules ([#&#8203;1695](https://github.com/gotenberg/gotenberg/issues/1695)). Thanks [@&#8203;sergeykad](https://github.com/sergeykad). - Updated the AWS Lambda Web Adapter to `1.1.0`, which supports Lambda SnapStart ([#&#8203;1704](https://github.com/gotenberg/gotenberg/issues/1704)). Thanks [@&#8203;michael-follmann](https://github.com/michael-follmann). - Bumped golangci-lint to `v2.15.0`. - Updated Go dependencies. </details> --- ### Configuration 📅 **Schedule**: (UTC) - Branch creation - At any time (no schedule defined) - Automerge - At any time (no schedule defined) 🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied. ♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR has been generated by [Mend Renovate CLI](https://github.com/renovatebot/renovate). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0NC4yMjEuMCIsInVwZGF0ZWRJblZlciI6IjQ0LjIyMS40IiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6WyJyZW5vdmF0ZSJdfQ==-->
Update docker.io/gotenberg/gotenberg Docker tag to v9
All checks were successful
/ build (pull_request) Successful in 31s
/ Ansible Lint (push) Successful in 3m43s
/ Ansible Lint (pull_request) Successful in 5m5s
ad01d577be
You can view your changes at https://staging.infra-docs.hamburg.ccc.de/pr186/
renovate force-pushed renovate/docker.io-gotenberg-gotenberg-9.x from ad01d577be
All checks were successful
/ build (pull_request) Successful in 31s
/ Ansible Lint (push) Successful in 3m43s
/ Ansible Lint (pull_request) Successful in 5m5s
to 0dfaa68d96
All checks were successful
/ build (pull_request) Successful in 32s
/ Ansible Lint (push) Successful in 2m37s
/ Ansible Lint (pull_request) Successful in 2m37s
2026-11-06 03:17:46 +01:00
Compare
All checks were successful
/ build (pull_request) Successful in 32s
Required
Details
/ Ansible Lint (push) Successful in 2m37s
Required
Details
/ Ansible Lint (pull_request) Successful in 2m37s
Required
Details
This pull request doesn't have enough approvals yet. 0 of 1 approvals granted.
You are not authorized to merge this pull request.
View command line instructions

Checkout

From your project repository, check out a new branch and test the changes.
git fetch -u origin 'renovate/docker.io-gotenberg-gotenberg-9.x:renovate/docker.io-gotenberg-gotenberg-9.x'
git switch 'renovate/docker.io-gotenberg-gotenberg-9.x'
Sign in to join this conversation.
No description provided.