Repository navigation
[DEFECT] /dA/ shorty URLs treat filenames like 500w.jpg or 533637w.pdf as resize filters; on libvips an uncapped PDF resize can OOM the pod #38003
Description
Problem Statement
ShortyServlet applies its transform regexes (/(\d+)w\b, h, cw, ch, q, maxw, minw, …) to the whole lowercased URI, and everything after the field name is treated as a filter. A real filename that happens to look like a token is therefore parsed as a transform:
- Wrong bytes served. An image named
500w.jpgrequested via its direct link comes back resized to 500px wide and re-encoded. The visitor never gets the file they asked for. - Non-images enter the image pipeline. A PDF named
300w.pdfis routed to/contentAsset/imagebecausewidth > 0setsisImage, and is rasterized to a PNG instead of served raw.ImageUriPathExpanderre-applies the same patterns to each token, filename included, and appends/resize_w/N. - Uncapped libvips resize can crash the pod.
VipsResizeImageFiltersizes the output withResizeCalcand callsthumbnailImage(..., SIZE_FORCE)without theIMAGE_MAX_PIXEL_SIZE(default 5000) clamp thatVipsImageFilterApiImpland the legacyImageFilterApiImplapply. A name like533637w.pdfrequests a resize to 533,637px wide on a PDF rendered to an image. libvips allocates natively outside the JVM heap, so the container hits its memory limit and the kernel OOM-kills the process. The libvips→legacy fallback never runs.IMAGE_GENERATION_SIMULTANEOUS_REQUESTSstill allows several concurrent renders.
Impact: An environment on libvips can go into repeated OOM crash loops. A request that exceeds the load balancer timeout gets retried by the CDN, so renders pile up. Workarounds are renaming the asset or disabling libvips (DOT_IMAGE_API_USE_LIBVIPS=false), and the second one removes AVIF output. The h, cw, ch, maxw and minw patterns are affected the same way.
Steps to Reproduce
Local build 1.0.0-SNAPSHOT (built 2026-10-10), default image engine settings. The production environment ran 26.09.02.
- Create a content type with two binary fields (
file1,diagram1). - Upload a 1200×800 JPEG named
500w.jpgtodiagram1, and a 1-page PDF named300w.pdftofile1. Upload a control PDF namedplain.pdftofile1. Publish all three. - Request each direct link with no transform tokens:
/dA/<id>/diagram1/500w.jpg→image/png, 500×333, 215,826 bytes. The original is a 52,974-byte, 1200×800 JPEG./dA/<id>/file1/300w.pdf→image/png, 300×200. The original is a PDF./dA/<id>/file1/plain.pdf→application/pdf, hash identical to the upload. This is the control.
- (Memory impact) On libvips, request a PDF with a very large leading number, e.g.
/dA/<id>/file1/533637w.pdf. A render of this kind exhausts native memory. Production thread dumps show the request threads inVipsResizeImageFilter→vips_cache_operation_build, with a heap of 0.7 GiB and a container at the 14 GiB limit.
Expected: a filename is never parsed as a transform token, and non-image assets are served raw. Transform size is always clamped, whichever engine is configured.
Actual: as in step 3.
Acceptance Criteria
- An asset whose filename matches a token pattern (
500w.jpg,533637w.pdf,300h.png, and thecw,ch,q,maxw,minw,roforms), requested through its direct/dA/<id>/<field>/<filename>link, is served untransformed, with the original bytes and content type. - A non-image binary (e.g. a PDF) is never routed to
/contentAsset/imagebecause of its filename. - Every documented transform URL form still behaves as before (
/500w/photo.jpg,/webp,/jpeg,/jpegp,/avif,/smart,NNw,NNh,NNq,NNcw,NNch,NNmaxw,NNmaxh,NNminw,NNminh,NNro,fp), byte-for-byte for CDN-cached URLs. -
VipsResizeImageFilter(and any other libvips resize path) honoursIMAGE_MAX_PIXEL_SIZE. A single request with an oversized target cannot allocate unbounded native memory. - Behaviour is identical under the default libvips engine and
IMAGE_API_USE_LIBVIPS=false. - Regression tests cover a filename/token collision for numeric tokens, alongside the format-token cases in [DEFECT] Asset filenames starting with an image format token (webp-, jpeg-, avif-) are silently converted on /dA/ links #37534.
dotCMS Version
Reproduced on a local 1.0.0-SNAPSHOT build (2026-10-10). Observed in production on 26.09.02 and, per infrastructure metrics, already present on 26.08.19-04. Code is present on main.
Severity
High - Major functionality broken
Notes for whoever picks this up
- Relevant code:
ShortyServlet.java(thewidthPattern/heightPatterndefinitions andisImageat ~L358),ImageUriPathExpander.java,vips/VipsResizeImageFilter.java. - Possible directions, none prescribed: treat a trailing segment that has a file extension as the filename, never as a filter (
/500w/photo.jpgstill works); only route to the image path for image binaries; clamp libvips resizes and limit concurrency. A change that breaks the/<field>/NNwform would need a migration path, because those URLs are public and CDN-cached. - Byte-range requests skip the resize path, which is why partial PDF downloads kept working in production.
Links
- Freshdesk ticket 39762
- Related: [DEFECT] Asset filenames starting with an image format token (webp-, jpeg-, avif-) are silently converted on /dA/ links #37534 (same bug class, format tokens), [DEFECT] WebP images uploaded to Binary fields fail to load via their direct link #33615, Issue 34144 webp images failing to render #34379
Metadata
Metadata
Assignees
Labels
Type
Projects
- StatusShow more project fieldsNew
Activity