# Grav: Missing admin.super guard on core group blueprint access field allows admin.users operator to escalate to super-admin

Grav's group blueprint access field lacked the security@: admin.super guard, letting an admin.users operator save admin.super:true into a group ACL and become super-admin.

- Payout: Research
- Severity: high
- Program: Grav
- Found by: manus-use
- Disclosed: 2026-09-17
- CVE: CVE-2026-75837
- Write-up quality: 8/10
- Original: https://github.com/advisories/GHSA-xhfv-7758-r9hx
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-xhfv-7758-r9hx
- Tags: area:web domain:web impact:privesc impact:rce kind:research platform:ghsa sev:high tech:php technique:incomplete-fix technique:source-review vuln:access-control vuln:auth-bypass vuln:privilege-escalation

**Target:** Flex group blueprint access field (system/blueprints/user/group.yaml) via admin group-edit endpoint
**Root cause:** The group access field in group.yaml lacks the `security@: admin.super` guard that account.yaml carries, so Blueprint::dynamicSecurity never marks it validate.ignore and BlueprintSchema::filterArray retains the nested admin.super:true leaf. check_authorize has no PHP enforcement, leaving security@ as the sole control.
**Steps:**
1. Authenticate as a non-super operator holding `admin.users.update` and member of group `ops`.
2. POST `/admin/accounts/groups/ops` (or groups.json task:save) with body `data[access][admin][super]=1`.
3. Blueprint dynamicSecurity does not flag the field (no `security@`), filterArray keeps it, Validation passes the bool leaf.
4. FlexObject::update -> filter -> save persists to `user://config/groups.yaml` as `ops: { access: { admin: { super: true } } }`.
5. Next request, UserGroupObject::authorize('admin.super') returns true for all group members.
**How found:** Compared the group blueprint against the sibling account blueprint fixed by CVE-2026-42613: account.yaml has `security@: admin.super` on access/groups fields while group.yaml's access block has none. Confirmed via git log -S 'security@' that the guard never existed, and grep that check_authorize has zero PHP consumers, making security@ the only real strip.
**Exploitation:** A delegated admin.users operator edits a group they belong to (or creates one) and injects access[admin][super]=true; the value survives blueprint filtering and is persisted to groups.yaml, granting super-admin to every member on the next request, enabling scheduler/cron RCE and Twig eval.
**Escalation:** Super-admin grants admin panel access, scheduler cron execution and Twig evaluation, i.e. RCE; arbitrary rewrite of any group's ACL is itself an escalation primitive.
**Insight:** When a fix adds a blueprint-level `security@` guard to one field, audit every functionally-identical field in sibling blueprints (group vs account ACLs) — and verify whether the field's other flags like `check_authorize` are actually enforced in PHP before trusting them as controls.

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

**POST group access admin.super escalation**

```
POST /admin/accounts/groups/ops   (or groups.json task:save)
data[access][admin][super]=1
```

