GHSA-3W32-23WJ-RXG3

Vulnerability from github – Published: 2026-07-02 20:03 – Updated: 2026-07-02 20:03
VLAI
Summary
Craft CMS Vulnerable to Unauthorized Deletion of Destination Folders During Forced Moves
Details

We have identified an authorization issue in Craft CMS where a forced folder move can delete a conflicting destination folder without destination delete permission.

Description

Craft CMS’s craft\\controllers\\AssetsController::actionMoveFolder() supports moving an asset folder into a destination parent folder. If a folder with the same name already exists at the destination, the action can be called with force=true to overwrite the destination.

The permission checks for this action allow:

  • deleteAssets:<sourceVolumeUid> for the folder being moved
  • createFolders:<destVolumeUid> for the destination parent folder
  • saveAssets:<destVolumeUid> for the destination parent folder

The action does not require deleteAssets on the destination volume or destination conflict folder. When force=true and a name conflict exists, the code deletes the destination folder to resolve the conflict.

$this->requireVolumePermissionByFolder('deleteAssets', $folderToMove);
$this->requireVolumePermissionByFolder('createFolders', $destinationFolder);
$this->requireVolumePermissionByFolder('saveAssets', $destinationFolder);

src/controllers/AssetsController.php:L751-L753

Indexed destination conflicts are deleted via the Assets service:

$assets->deleteFoldersByIds($existingFolder->id);

src/controllers/AssetsController.php:L798-L798

Unindexed destination conflicts are deleted directly in the volume filesystem:

$targetVolume->deleteDirectory(rtrim($destinationFolder->path, '/') . '/' . $folderToMove->name);

src/controllers/AssetsController.php:L815

Impact

A user who cannot delete assets in a destination volume can still delete a destination folder and its contents by triggering a forced move into a conflicting name. This can cause asset loss, broken references in entries and fields that point to deleted assets, and operational disruption.

Show details on source website

{
  "affected": [
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "craftcms/cms"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "5.0.0-RC1"
            },
            {
              "fixed": "5.9.21"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    },
    {
      "package": {
        "ecosystem": "Packagist",
        "name": "craftcms/cms"
      },
      "ranges": [
        {
          "events": [
            {
              "introduced": "4.0.0-RC1"
            },
            {
              "fixed": "4.17.14"
            }
          ],
          "type": "ECOSYSTEM"
        }
      ]
    }
  ],
  "aliases": [
    "CVE-2026-50282"
  ],
  "database_specific": {
    "cwe_ids": [
      "CWE-862"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-07-02T20:03:58Z",
    "nvd_published_at": "2026-07-02T17:17:01Z",
    "severity": "HIGH"
  },
  "details": "We have identified an authorization issue in Craft CMS where a forced folder move can delete a conflicting destination folder without destination delete permission.\n\n### Description\n\nCraft CMS\u2019s `craft\\\\controllers\\\\AssetsController::actionMoveFolder()` supports moving an asset folder into a destination parent folder. If a folder with the same name already exists at the destination, the action can be called with `force=true` to overwrite the destination.\n\nThe permission checks for this action allow:\n\n- `deleteAssets:\u003csourceVolumeUid\u003e` for the folder being moved  \n- `createFolders:\u003cdestVolumeUid\u003e` for the destination parent folder  \n- `saveAssets:\u003cdestVolumeUid\u003e` for the destination parent folder\n\nThe action does not require `deleteAssets` on the destination volume or destination conflict folder. When `force=true` and a name conflict exists, the code deletes the destination folder to resolve the conflict.\n\n```php\n$this-\u003erequireVolumePermissionByFolder(\u0027deleteAssets\u0027, $folderToMove);\n$this-\u003erequireVolumePermissionByFolder(\u0027createFolders\u0027, $destinationFolder);\n$this-\u003erequireVolumePermissionByFolder(\u0027saveAssets\u0027, $destinationFolder);\n```\n\n[*src/controllers/AssetsController.php:L751-L753*](https://github.com/craftcms/cms/blob/5.x/src/controllers/AssetsController.php#L751-L753)\n\nIndexed destination conflicts are deleted via the Assets service:\n\n```php\n$assets-\u003edeleteFoldersByIds($existingFolder-\u003eid);\n```\n\n[*src/controllers/AssetsController.php:L798-L798*](https://github.com/craftcms/cms/blob/5.x/src/controllers/AssetsController.php#L798-L798)\n\nUnindexed destination conflicts are deleted directly in the volume filesystem:\n\n```php\n$targetVolume-\u003edeleteDirectory(rtrim($destinationFolder-\u003epath, \u0027/\u0027) . \u0027/\u0027 . $folderToMove-\u003ename);\n```\n\n[*src/controllers/AssetsController.php:L815*](https://github.com/craftcms/cms/blob/5.x/src/controllers/AssetsController.php#L815)\n\n### Impact\n\nA user who cannot delete assets in a destination volume can still delete a destination folder and its contents by triggering a forced move into a conflicting name. This can cause asset loss, broken references in entries and fields that point to deleted assets, and operational disruption.",
  "id": "GHSA-3w32-23wj-rxg3",
  "modified": "2026-07-02T20:03:58Z",
  "published": "2026-07-02T20:03:58Z",
  "references": [
    {
      "type": "WEB",
      "url": "https://github.com/craftcms/cms/security/advisories/GHSA-3w32-23wj-rxg3"
    },
    {
      "type": "ADVISORY",
      "url": "https://nvd.nist.gov/vuln/detail/CVE-2026-50282"
    },
    {
      "type": "WEB",
      "url": "https://github.com/craftcms/cms/commit/2c2579c7f1030872423f268d0c8b48377101961d"
    },
    {
      "type": "PACKAGE",
      "url": "https://github.com/craftcms/cms"
    }
  ],
  "schema_version": "1.4.0",
  "severity": [
    {
      "score": "CVSS:4.0/AV:N/AC:L/AT:N/PR:L/UI:N/VC:N/VI:H/VA:N/SC:N/SI:N/SA:N",
      "type": "CVSS_V4"
    }
  ],
  "summary": "Craft CMS Vulnerable to Unauthorized Deletion of Destination Folders During Forced Moves"
}



Log in or create an account to share your comment.




Tags
Taxonomy of the tags.


Loading…

Loading…

Loading…

Forecast uses a logistic model when the trend is rising, or an exponential decay model when the trend is falling. Fitted via linearized least squares.

Sightings

Author Source Type Date Other

Nomenclature

  • Seen: The vulnerability was mentioned, discussed, or observed by the user.
  • Confirmed: The vulnerability has been validated from an analyst's perspective.
  • Published Proof of Concept: A public proof of concept is available for this vulnerability.
  • Exploited: The vulnerability was observed as exploited by the user who reported the sighting.
  • Patched: The vulnerability was observed as successfully patched by the user who reported the sighting.
  • Not exploited: The vulnerability was not observed as exploited by the user who reported the sighting.
  • Not confirmed: The user expressed doubt about the validity of the vulnerability.
  • Not patched: The vulnerability was not observed as successfully patched by the user who reported the sighting.

Loading…

Loading…

Loading…

Related by attack behaviour

Vulnerabilities whose description is nearest to this one in the vector space of the CIRCL/vulnerability-attack-technique-biencoder model. This is a similarity search over the bi-encoder space (plain cosine), not a classification, and it has no measured accuracy.


Loading…