Packagist · craftcms/cms
Craft CMS: Authorization bypass in `entries/move-to-section` via missing target-section save check
The EntriesController::actionMoveToSection() endpoint checks only whether the current user can view the destination section, but it does not require permission to save entries into that section. A low-privileged authenticated control-panel user who can move an entry out of its current section can therefore move that entry into a different section where they have read access but no write access.
The vulnerable route is implemented in EntriesController.php:465:
The destination check is only viewEntries:$section->uid . The source-entry gate is Entry::canMove(), which verifies whether the user can move the existing entry based on the source section:
This closes the exploit chain:
entries/move-to-section.viewEntries, not saveEntries.moveEntryToSection() rewrites sectionId and saves the entry into the unauthorized section.Preconditions derived from the code:
345 is movable by the attacker from its current section.viewEntries on destination section 12.saveEntries:DESTINATION_UID, which is the missing check that makes the bypass possible.Result:
viewEntries:$section->uid passes.canMove() based on source-section permissions.moveEntryToSection() updates the entry’s sectionId and saves it.This breaks the intended section-level authorization model. A user with limited content permissions can inject or relocate content into a protected section, interfering with editorial boundaries, approval workflows, section-specific business logic, and content ownership expectations.
Is your project exposed to this? Stateward checks every dependency on every pull request and flags it only if your code actually reaches it.
Check my repoSources: CISA KEV (public domain), OSV.dev & GitHub Advisory Database (CC-BY-4.0), FIRST EPSS, NVD/CWE (public domain). Served live from the Stateward advisory database.