Skip to content

Commit 2c2579c

Browse files
committed
Merge branch '4.x-advisories' into 4.x
2 parents 0e48a96 + c13d539 commit 2c2579c

6 files changed

Lines changed: 32 additions & 23 deletions

File tree

CHANGELOG.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
# Release Notes for Craft CMS 4
22

3+
## Unreleased
4+
5+
- Fixed [high-severity](https://github.com/craftcms/cms/security/policy#severity--remediation) authorization bypass vulnerabilities. (GHSA-3w32-23wj-rxg3, GHSA-qh45-9g5p-m2v4)
6+
37
## 4.17.13.1 - 2026-04-14
48

59
- Fixed an issue that prevented Craft from being installed. ([#18700](https://github.com/craftcms/cms/issues/18700))

src/controllers/AssetsController.php

Lines changed: 18 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -422,8 +422,14 @@ public function actionReplaceFile(): Response
422422
throw new NotFoundHttpException('Asset not found.');
423423
}
424424

425-
$this->requireVolumePermissionByAsset('replaceFiles', $assetToReplace ?: $sourceAsset);
426-
$this->requirePeerVolumePermissionByAsset('replacePeerFiles', $assetToReplace ?: $sourceAsset);
425+
if ($assetToReplace) {
426+
$this->requireVolumePermissionByAsset('replaceFiles', $assetToReplace);
427+
$this->requirePeerVolumePermissionByAsset('replacePeerFiles', $assetToReplace);
428+
}
429+
if ($sourceAsset) {
430+
$this->requireVolumePermissionByAsset('replaceFiles', $sourceAsset);
431+
$this->requirePeerVolumePermissionByAsset('replacePeerFiles', $sourceAsset);
432+
}
427433

428434
// Handle the Element Action
429435
if ($assetToReplace !== null && $uploadedFile) {
@@ -740,11 +746,17 @@ public function actionMoveFolder(): Response
740746
throw new BadRequestHttpException('The destination folder does not exist');
741747
}
742748

743-
// Check if it's possible to delete objects in the source volume, create folders
744-
// in the target volume, and save assets in the target volume.
745-
$this->requireVolumePermissionByFolder('deleteAssets', $folderToMove);
746-
$this->requireVolumePermissionByFolder('createFolders', $destinationFolder);
749+
// Make sure the user has permission to move the source folder
750+
// (same permissions checked for `data-movable`)
751+
$this->requireVolumePermissionByFolder('savePeerAssets', $folderToMove);
752+
$this->requireVolumePermissionByFolder('deletePeerAssets', $folderToMove);
753+
754+
// Make sure the user has permission to move folders into the target folder
755+
// (same permissions checked for `data-can-move-to`)
747756
$this->requireVolumePermissionByFolder('saveAssets', $destinationFolder);
757+
$this->requireVolumePermissionByFolder('deleteAssets', $destinationFolder);
758+
$this->requireVolumePermissionByFolder('savePeerAssets', $destinationFolder);
759+
$this->requireVolumePermissionByFolder('deletePeerAssets', $destinationFolder);
748760

749761
$targetVolume = $destinationFolder->getVolume();
750762

src/elements/Asset.php

Lines changed: 3 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -903,9 +903,9 @@ private static function _assembleSourceInfoForFolder(VolumeFolder $folder, ?User
903903

904904
$userSession = Craft::$app->getUser();
905905
$canUpload = $userSession->checkPermission("saveAssets:$volume->uid");
906-
$canMoveTo = $canUpload && $userSession->checkPermission("deleteAssets:$volume->uid");
907-
$canMovePeerFilesTo = (
908-
$canMoveTo &&
906+
$canMoveTo = (
907+
$canUpload &&
908+
$userSession->checkPermission("deleteAssets:$volume->uid") &&
909909
$userSession->checkPermission("savePeerAssets:$volume->uid") &&
910910
$userSession->checkPermission("deletePeerAssets:$volume->uid")
911911
);
@@ -924,7 +924,6 @@ private static function _assembleSourceInfoForFolder(VolumeFolder $folder, ?User
924924
'folder-id' => $folder->id,
925925
'can-upload' => $folder->volumeId === null || $canUpload,
926926
'can-move-to' => $canMoveTo,
927-
'can-move-peer-files-to' => $canMovePeerFilesTo,
928927
'fs-type' => $fs::class,
929928
],
930929
];

src/web/assets/cp/dist/cp.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/web/assets/cp/dist/cp.js.map

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/web/assets/cp/src/js/AssetIndex.js

Lines changed: 5 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -58,7 +58,7 @@ Craft.AssetIndex = Craft.BaseElementIndex.extend(
5858
.filter(
5959
(source) =>
6060
Garnish.hasAttr(source, 'data-folder-id') &&
61-
Garnish.hasAttr(source, 'data-can-move-peer-files-to')
61+
Garnish.hasAttr(source, 'data-can-move-to')
6262
)
6363
);
6464
if (this.sourcePath.length <= 1) {
@@ -764,10 +764,7 @@ Craft.AssetIndex = Craft.BaseElementIndex.extend(
764764
},
765765
});
766766

767-
if (
768-
currentFolder.canMove &&
769-
this.getMoveTargetSourceKeys(true).length
770-
) {
767+
if (currentFolder.canMove && this.getMoveTargetSourceKeys().length) {
771768
actions.push({
772769
label: Craft.t('app', 'Move folder'),
773770
onSelect: () => {
@@ -895,18 +892,15 @@ Craft.AssetIndex = Craft.BaseElementIndex.extend(
895892
});
896893
},
897894

898-
getMoveTargetSourceKeys: function (peerFiles) {
899-
const attr = peerFiles
900-
? 'data-can-move-peer-files-to'
901-
: 'data-can-move-to';
895+
getMoveTargetSourceKeys: function () {
902896
return this.$sources
903897
.toArray()
904898
.filter((source) => {
905899
const volumeHandle = $(source).data('volume-handle');
906900
return (
907901
volumeHandle &&
908902
volumeHandle !== 'temp' &&
909-
Garnish.hasAttr(source, attr)
903+
Garnish.hasAttr(source, 'data-can-to')
910904
);
911905
})
912906
.map((source) => $(source).data('key'));
@@ -922,7 +916,7 @@ Craft.AssetIndex = Craft.BaseElementIndex.extend(
922916
}
923917

924918
new Craft.VolumeFolderSelectorModal({
925-
sources: this.getMoveTargetSourceKeys(true),
919+
sources: this.getMoveTargetSourceKeys(),
926920
showTitle: true,
927921
modalTitle: Craft.t('app', 'Move to'),
928922
selectBtnLabel: Craft.t('app', 'Move'),

0 commit comments

Comments
 (0)