Confine Media Manager and image resizer paths to their roots - #1553
LukeTowers wants to merge 1 commit into
Conversation
The Media Manager's thumbnail handlers now run every path they are given through `MediaLibrary::validatePath()`, the rule the rest of the widget and the media library already apply, so no handler in the widget is held to a looser one than its neighbours. The image resizer matches a path against its configured sources on a path boundary, and accepts only paths that stay inside the source folder it matched. The Crop & Insert handler keeps the folder and file name it was asked for, takes the stored file's extension from the image the resizer produced, and holds the result to `cms.fileDefinitions.defaultExtensions`, the extension allowlist that uploading and renaming a media item already use; a request names the image to crop by its URL, so that the resizer resolves it against those same configured sources. The thumbnail path is validated inside `generateThumbnail()`, alongside the widget's existing broken-thumbnail handling, rather than in the handler above it. The browser asks for thumbnails in batches, so one item the media library will not accept renders that item's broken thumbnail and leaves the rest of the batch alone. Behaviour changes: - A crop destination always uses the extension of the image the resizer produced; a requested extension is ignored, so cropping to a different extension than the source's no longer works. - A crop destination is checked against `cms.fileDefinitions.defaultExtensions`, the allowlist that media uploads and renames already use. Out of the box that list covers every format the resizer can produce, so nothing changes; a site that has narrowed it will find crops to the formats it removed refused, the way uploading and renaming them already are. - An empty, whitespace-only or non-string crop destination, and a crop source that is not a URL string, are now an "Invalid input data" error rather than a PHP error. - The batch thumbnail handler returns the widget's broken thumbnail, rather than a generated one, for a media item whose name falls outside the media library's own path rules. The Media Manager's uploader cannot produce such a name, and the sidebar preview, rename, move and crop already refuse one. The item grid builds its thumbnails while the page renders rather than through this handler, so a folder of such files looks the same as it did before. - The image resizer resolves a source path only while it stays inside the configured source folder it matched, and matches those sources on folder boundaries. `|resize` and the `image` list column fall back to the value they were given, as they already do for an image the resizer cannot identify; `|imageWidth` and `|imageHeight` report the failure, as they already do for the same. Tests: `System\Tests\Classes\ImageResizerTest::testRefusesPathsOutsideTheMatchedSource`, `::testRefusesARelativeSegmentThatWouldHaveStayedInsideTheSource` and `::testAcceptsPathsInsideTheMatchedSource`; the new `Backend\Tests\Widgets\MediaManagerThumbnailPathTest` (including `::testOneRefusedPathInABatchStillThumbnailsTheRestOfTheBatch` and `::testAnItemOutsideTheLibraryPathRulesOnlyLosesItsOwnThumbnail`) and `Backend\Tests\Widgets\MediaManagerCropDestinationTest` (including `::testCropRefusesASourceThatIsNotAUrl` and `::testTheStockExtensionAllowlistCoversEveryFormatTheResizerProduces`).
|
Navigate logical layers of code changes, visualize relationships, and explore their blast radius. No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Advanced Run ID: 📒 Files selected for processing (5)
Included review availability: This review used your included allowance. Your plan provides up to 4 included reviews per hour; 3 remain after this review. WalkthroughImageResizer now requires source-path boundary matches and rejects matched paths with traversal segments. MediaManager validates thumbnail paths and crop inputs. Crop destinations use the produced image format and must pass file-type validation. New tests cover rejected paths and inputs, batch thumbnail behavior, and accepted thumbnail and crop paths. Priority: ➖ Normal Estimated code review effort: 3 (Moderate) | ~25 minutes Merge Risk: ⚪ Minimal · up to The path-validation and crop-output changes have no identified issue requiring resolution before merge. Security Architecture ReviewSecurity architecture risk: 🔵 Low · up to The reviewed changes generally tighten path and file-type controls. No introduced security failure was established, but behavior with custom image sources and storage configurations remains uncertain. Retained concerns Security review detailsSecurity Blast Radius
Trust Boundaries and Controls
Resilience and Maintainability Implications
Hardening Proposals
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches 💡 1📝 Generate docstrings 💡
🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
The Media Manager's thumbnail handlers now run every path they are given through
MediaLibrary::validatePath(), the rule the rest of the widget and the media library already apply, so no handler in the widget is held to a looser one than its neighbours. The image resizer matches a path against its configured sources on a path boundary and accepts only paths that stay inside the source folder it matched. Crop & Insert keeps the folder and file name it was asked for, takes the stored file's extension from the image the resizer produced, and holds the destination tocms.fileDefinitions.defaultExtensions, the same extension allowlist that uploading and renaming a media item already use.Thumbnail validation lives inside
generateThumbnail(), next to the widget's existing broken-thumbnail handling, rather than in the handler above it. The browser requests thumbnails in batches, so an item the media library will not accept renders that one item's broken thumbnail and leaves the rest of the batch alone.Behaviour changes
cms.fileDefinitions.defaultExtensions. Out of the box that list covers every format the resizer can produce, so nothing changes; a site that has narrowed it will find crops to the formats it removed refused, the way uploading and renaming them already are.Invalid input dataerror rather than a PHP error.|resizeand theimagelist column fall back to the value they were given, as they already do for an image the resizer cannot identify;|imageWidthand|imageHeightreport the failure, as they already do for the same.Tests
System\Tests\Classes\ImageResizerTest::testRefusesPathsOutsideTheMatchedSource,::testRefusesARelativeSegmentThatWouldHaveStayedInsideTheSource,::testAcceptsPathsInsideTheMatchedSourceBackend\Tests\Widgets\MediaManagerThumbnailPathTest, including::testOneRefusedPathInABatchStillThumbnailsTheRestOfTheBatchand::testAnItemOutsideTheLibraryPathRulesOnlyLosesItsOwnThumbnailBackend\Tests\Widgets\MediaManagerCropDestinationTest, including::testCropRefusesASourceThatIsNotAUrland::testTheStockExtensionAllowlistCoversEveryFormatTheResizerProduces19 of the 26 Media Manager tests and 11 of the 25 resizer tests fail without the production changes in this PR.
modules/backendis green at 354 tests / 864 assertions andmodules/systemat 364 / 1933, both on PHP 8.4 locally;phpcsis clean on the changed files.Summary by CodeRabbit