- Shipped
- September 23, 2026 at 10:34 AM UTC
- Author
- Kamo
- Commit
- cb37067
ResourceServerConfig permits every request (this service is reachable anonymously at conversion-api.kamocrm.com), and none of ImageOpsController's or ConversionController's handlers checked a session or an internal secret of their own — ffmpeg and LibreOffice ran, and Batik transcoded raw SVG, on anonymous uploads. Mapped every caller across the fleet before touching auth, because most of these endpoints have service-to-service callers (docsservice, securityservice) that send NO credential today: - /image/resize-height: gated on a staff session (extractKToken, the same gate ImagingUploadController applies) — its one caller, the email-signature badge settings page, is itself unreachable without one, so this costs it nothing. - /convert-to-pdf-with-password: gated on the **************** shared secret (same constant-time, fail-closed pattern as TranscriptionController) — a full repo grep found NO caller anywhere, so gating it is free. - /image/resize-bg, /favicon/generate, /convert-to-pdf, /generate-thumbnails, /page-count, /render-page: NOT gated. Each has at least one Java service-to-service caller that sends no X-Internal-Auth today (securityservice's **************** ConversionPageClient, docsservice's DocumentService). Requiring auth here would 401 that traffic immediately on deploy — a product/cross-repo decision, not a guess this change makes unilaterally. Full caller map, and the property **************** / **************** already mounted on this pod per the previous commit) each caller needs to start sending, goes in the fix report. Hardened independently of the auth gap, since none of it depends on caller coordination: - ImageResizeService: neither ffprobe nor ffmpeg was ever told the input format — both auto-detected across ffmpeg's full demuxer set from file content. Now sniffed from magic bytes against a fixed allowlist (PNG/JPEG/WebP/GIF/BMP → the matching *_pipe demuxer) and pinned on both invocations; anything else is refused before a process is spawned. - FaviconGeneratorService: SVG input goes through a locked-down PNGTranscoder (NoLoadExternalResourceSecurity + NoLoadScriptSecurity, rather than relying on Batik's own default policy for this input shape — verified by hand that Batik 1.17 already defaults both off here, but that is now a guarantee this file states and a test pins, not an unstated dependency-version property) and refuses a DOCTYPE outright (the XXE vector; verified this one DOES matter — Batik does not reject it on its own). Added the same pre-decode pixel cap (~100MP, via ImageIO's header-only reader) and concurrency limit (2 in flight) the resize endpoints already had, plus a 2MB cap on the SVG markup itself. New/updated tests: ImageResizeServiceTest (format allowlist), FaviconGeneratorServiceTest (SSRF via a local HTTP server that must see zero hits, DOCTYPE refusal, oversized-SVG refusal), **************** **************** Mutation-checked: the DOCTYPE, format-allowlist and both new auth gates all go red when disabled; the SSRF test does not (see its docstring — Batik already defends this input shape) but is kept as a pinned regression guard.
