Repository navigation
v1.3.0
Upgrading from 1.2.1
No format or env var was removed, and no database migration runs; /redoc, which rendered empty, is switched off. Every deployment should update: this release carries the fixes for critical advisories in the Python packages Pillow (GHSA-8g5g-8vmr-9782), certifi (GHSA-6q48-6c7w-9gw2) and brotli (CVE-2026-111497), and for two medium ones in the libheif that pillow-heif bundles (GHSA-9c75-9g8r-4728, GHSA-vv35-6hxg-95x8); see the Security entries in the changelog. Still accepted until 2026-11-02, because Swagger UI does not use the options they need: five DOMPurify advisories in the Swagger UI bundle on /docs, one rated critical and one high upstream (listed in docs/security-overview.md). Check before pulling:
- Pinned to
1.2or1.2.1(or their-officevariants): there is no 1.2.2, so these image tags stay on 1.2.1 without the fixes. Move to1.3(or1.3.0); for a backport onto 1.2, write tosecurity@filemorph.io. - New setting:
LOCAL_TOOLS_ENABLED(defaultfalse) prepares processing in the browser. Left off, nothing changes. FastAPI's automatic OpenTelemetry exporter setup now needsFASTAPI_OTEL_AUTO_CONFIGURE=true; this concerns only an install that added an OpenTelemetry SDK itself, as the image ships none. - New refusals: the table conversions (XLSX → CSV, CSV → XLSX, CSV → JSON, JSON → CSV) and PDF compression now run in a child process, as PDF → TXT already did, and stop after 90 seconds; on Linux the child is also capped at 1 GiB of address space (PDF compression: 3 GiB) and 2 GiB per file written (PDF compression and PDF → TXT: 1 GiB). A file past a limit gets
400(invalid_input; PDF compression:pdf_too_complex) with the next step in the message. With pypdf 6.21 a few rare PDFs that 1.2.1 read now get the "could not read" message. - Target sizes: a result is now at most the target, no longer up to 3 % (PDF: 5 %) above it. Where even the lowest quality is too big, images, and a PDF's embedded images, are scaled down; such results say so in
X-FileMorph-Warnings, the newX-FileMorph-Batch-Notesheader andmanifest.json, which a batch ZIP now also carries when no file failed. On/pdf/compress,X-FileMorph-Convergednow means "at most the target". - Messages and codes: the limit messages no longer say "upgrade your plan"; they name a free account where accounts exist, or self-hosting. New error codes:
pdf_too_complexandbatch_too_large, and for the new video → GIF conversionvideo_too_longandvideo_too_complex. A file part with no file in it, which a plain browser form sends for an empty file input, now counts as missing: the upload routes answer the generic422, and a batch that also carries real files leaves it out. A client that matches message texts needs updating. - Instances without accounts (no
DATABASE_URL): no Sign In link, and the account pages answer 404. APP_BASE_URL: the home page's curl example now targets it on every instance instead of filemorph.io; left at the default it showshttp://localhost:8000.- Compose and systemd:
docker-compose.ymlcaps the container at 4096 processes and threads and turns off core dumps. The systemd unit indocs/self-hosting.mdgains the same limits plusNoNewPrivileges=yes,PrivateTmp=yesandProtectSystem=strict; a compose file or unit copied earlier can take them over. WhereMAX_GLOBAL_CONCURRENCYwas raised on a host with many cores, raise the cap too (about 200, plus 3 per CPU core for each parallel conversion; "Capacity tuning" indocs/self-hosting.md). - Logs: logged errors keep their type and traceback but no longer their text unless
APP_DEBUG=true; the WeasyPrint, fontTools and pypdf loggers are silent; a child stopped at its CPU-time limit shows status-9. An alert rule that matched error texts needs a new pattern. - Image and TLS: the image moves to the python:3.14-slim build of 2026-10-21 (Python 3.14.8, a CA store without the compromised emSign root). Installed without the image, update the operating system's ca-certificates package: outgoing mail trusts it.
The full list of changes is in CHANGELOG.md.
What's Changed
- fix(docs): serve the API explorer from our own origin — /docs works under the CSP again by @MrChengLen in #243
- fix(logs): logged errors keep their type and location, not their text by @MrChengLen in #241
- ci(security): check vendored browser code against OSV — blocking like pip-audit by @MrChengLen in #244
- fix(convert): tables and PDF compression run in their own process — stopped after 90 s, 1 or 3 GiB on Linux by @MrChengLen in #242
- deps(security): certifi 2026.10.19 + Pillow 13.0.0 — critical advisories by @MrChengLen in #245
- fix(privacy): the privacy notice names every right, the Cloudflare transfer and a 30-day log limit by @MrChengLen in #240
- fix(convert): the log names a failed child's error type — its text stays out, as since #241 by @MrChengLen in #246
- feat(pricing): FileMorph is free — pricing page, navigation and account texts say so by @MrChengLen in #248
- fix(security): emSign root gone — Stripe via certifi, base image with Debian fix by @MrChengLen in #247
- feat(pdf): pdf_too_complex — the compress page links on to Extract PDF pages by @MrChengLen in #250
- fix(convert): read CSV uploads as a stream — memory follows the longest row by @MrChengLen in #249
- feat(limits): limit messages name the free way past a limit — no "upgrade your plan" by @MrChengLen in #251
- feat(ui): every processing button says where the work runs — "via our server" by @MrChengLen in #253
- feat(engine): hash-pinned engine mount and CSP profiles — off by default by @MrChengLen in #255
- fix(limits): free account only where accounts exist — batch-size 400 in German by @MrChengLen in #254
- deps: pypdf 6.21.2, opentelemetry-api 1.45.1 — unblock CI; 3 DOMPurify advisories accepted to 2026-11-02 by @MrChengLen in #257
- fix(accounts): no sign-in links without accounts — account pages 404 there by @MrChengLen in #258
- deps: brotli 1.2.1 — fixes CVE-2026-111497 in the decoder by @MrChengLen in #260
- feat(convert): file size limit for conversion children — tables 2 GiB, PDF 1 GiB by @MrChengLen in #252
- feat(convert): hard limits for the conversion children — soft and hard alike by @MrChengLen in #256
- feat(compress): the target size is an upper bound — scale down when quality can't reach it by @MrChengLen in #261
- docs(changelog): release 1.3.0 — fold changelog.d, bump the version by @MrChengLen in #265
- deps: python-all batch — FastAPI 0.154, Pydantic 2.14, SQLAlchemy 2.1.5, uv 0.13.4 (supersedes #259) by @MrChengLen in #263
- feat(convert): video → GIF — two-pass palette, 30-second limit, never cut short by @MrChengLen in #266
- feat(convert): children isolate themselves further — no forks, no new privileges by @MrChengLen in #262
- docs(changelog): 1.3.0 re-fold — libheif, video → GIF, child isolation by @MrChengLen in #270
Full Changelog: v1.2.1...v1.3.0