# Craft CMS Vulnerable to Privilege Escalation/Bypass through UsersController->actionImpersonateWithToken()

Craft CMS preview token accepted by impersonate-with-token action lets any low-privilege or unauthenticated user log in as admin.

- Payout: Research
- Severity: high
- Program: Craft CMS
- Found by: carlini
- Disclosed: 2026-03-16
- CVE: CVE-2026-32267
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-cc7p-2j3x-x7xf
- Library page: http://bugbountylibrary.com/r/ghsa%3AGHSA-cc7p-2j3x-x7xf
- Tags: area:web domain:web impact:ato impact:privesc kind:research platform:ghsa sev:high tech:php technique:source-review vuln:access-control vuln:auth-bypass vuln:privilege-escalation

**Target:** UsersController actionImpersonateWithToken endpoint
**Root cause:** actionPreview() re-dispatches with skipSpecialHandling=true and checkToken=false, letting an attacker-controlled action param override the dispatch target; requireToken() only checks a boolean _hadToken set by any previously resolved token, not that it was issued for impersonation.
**Steps:**
1. Log in as editor, create a Section/Entry, click Preview
2. Inspect the preview iframe src `http://host/blog/title?x-craft-live-preview=...&token=XXXXXXXX` and copy the token value
3. In incognito navigate to `http://host/?token=XXXXXXXX&action=users/impersonate-with-token&userId=1&prevUserId=1` (404 expected)
4. Navigate to `/admin` in same tab; land authenticated as admin
**How found:** Noticed actionPreview() re-dispatch passes skipSpecialHandling=true and checkToken=false, then observed requireToken() only checks the _hadToken boolean rather than token-to-action binding, and that actionImpersonateWithToken is in $allowAnonymous.
**Exploitation:** Attacker with any valid preview token (trivially obtained by an editor via Preview) appends action=users/impersonate-with-token&userId=1&prevUserId=1 to a tokenized URL; the re-dispatch bypasses guards and requireToken() passes on the boolean, logging the attacker in as user 1 (admin) with no credentials.
**Escalation:** Low-privilege editor escalates to full admin; unauthenticated users holding a shared preview URL can do the same.
**Insight:** When a framework re-dispatches requests internally with security guards disabled, check whether the action query param is attacker-controllable and whether token guards bind the token to the specific action rather than just 'a token was seen'.

## Proof of concept (copied exactly from the original report)

**Exploit URL impersonating admin with preview token**

```
http://host:18895/?token=XXXXXXXX&action=users/impersonate-with-token&userId=1&prevUserId=1
```

