CVE-2026-50279High▾ TwilightCraft CMS: Authorship spoofing in `entries/save-entry` via pre-check/post-mutation authorization gap
▾ Twilight zone — High severity, or a signal on a lesser flaw
impact 41.3 · likelihood 0.1 · exploitation 0
Need a working PoC? Pro members can cast a request and our team develops one — it lands right here.
Exploit-prediction probability, daily snapshots since Jul 4.
Disclosure to exploitation, from the record and what we observed since indexing it.
Disclosed via GHSA
0.2%
0.2% → 0.4%
EntriesController::actionSaveEntry() performs entry-edit permission checks before request-controlled author changes are applied to the model. The subsequent author mutation path accepts attacker-supplied authors / author parameters and allows the change when the current user is one of the old authors. Because the controller does not re-run authorization after mutating the author list, a low-privileged user can reassign an entry’s authorship to another user without holding the dedicated peer-author-change permission.
The control flow begins in EntriesController.php:249. actionSaveEntry() loads the entry and enforces edit permissions before calling _populateEntryModel():
public function actionSaveEntry(bool $duplicate = false): ?Response
{
...
$entry = $this->_editableEntry($this->request->getBodyParam('entryId'), $siteId);
...
$this->enforceEditEntryPermissions($entry, $duplicate);
...
$this->_populateEntryModel($entry);
...
$success = Craft::$app->getElements()->saveElement($entry);
}
The attacker-controlled source is in EntriesController.php:588:
$entry->setAttributesFromRequest(array_filter([
'authorIds' => $this->request->getBodyParam('authors') ??
$this->request->getBodyParam('author') ??
$entry->getAuthorId() ??
static::currentUser()->id,
]));
Entry::setAttributesFromRequest() in Entry.php:1124 extracts the new author IDs and applies them if canChangeAuthor() returns true:
if (
($authorIds !== null || $authorId !== null) &&
$this->canChangeAuthor()
) {
$this->_oldAuthorIds = $oldAuthorIds;
$this->setAuthorIds($authorIds);
}
canChangeAuthor() at Entry.php:2789 allows the author change when the current user can view peer entries and is already one of the existing authors:
return (
empty($authorIds) ||
in_array($user->id, $authorIds) ||
$user->can("changeAuthorForPeerEntries:$section->uid")
);
After the author list is mutated, the controller does not re-check authorization.
This closes the exploit chain:
entries/save-entry with attacker-controlled authors[].Preconditions derived from the source:
345.345, or otherwise satisfies canChangeAuthor() through the old author set.viewPeerEntries for the section.1 exists and can be assigned as an author in that section.Result:
enforceEditEntryPermissions() succeeds on the original entry state._populateEntryModel() reads authors[]=1 from the request body.setAttributesFromRequest() updates authorIds because canChangeAuthor() is evaluated against the old authorship state.saveElement() persists the change and _saveAuthors() rewrites the entry-author relation.345 now appears authored by user 1.This allows low-privileged users to falsify content ownership and alter the authorship of entries without having the dedicated author-management permission. The impact includes corrupted audit trails, misleading notifications, broken approval workflows, and unauthorized reassignment of content responsibility.
craftcms/cms >= 5.0.0-RC1, < 5.9.21Upgrade to a patched release:
craftcms/cms 5.9.21Connected by shared product, vendor, weakness, or advisory.
GHSA-p8x7-9vfw-p7vcHighCraft CMS: Arbitrary user password reset leading to administrator account takeover
GHSA-xxpx-f366-4xpqMediumCraft CMS:Authorization bypass: view-only Categories user can modify category structure via structures/move-element
GHSA-wg23-69c2-gjc8CriticalCraft CMS: Passkey login accepts replayed WebAuthn assertions
GHSA-2rp4-x2j7-qmccMediumCraft CMS: Stored XSS in the control panel via unescaped draft name
GHSA-7hxc-f267-h5q7LowCraft CMS: Incorrect path validation could potentially lead to path traversal
GHSA-rvmm-v933-jgxqMediumCraft CMS: Missing authorization check allows non-admin control panel users access to user registration metrics