VYPR
High severity7.7GHSA Advisory· Published May 11, 2026· Updated May 12, 2026

CVE-2026-42845

CVE-2026-42845

Description

The form plugin for Grav adds the ability to create and use forms. Prior to 9.1.0 , there is an unauthenticated page-content overwrite via file upload (GHSA-w4rc-p66m-x6qq). Public form uploads now strip path components from the POST-supplied filename and hard-block page-content extensions (md, yaml, yml, json, twig, ini) regardless of the configurable dangerous-extensions list. A permissive accept policy combined with the default destination: self@ could otherwise let an attacker overwrite the page's own .md and pivot to super-admin via a process: save action. This vulnerability is fixed in 9.1.0.

Affected products

1

Patches

1
48bacc4187e1

[security] block page-content overwrite via form upload (GHSA-w4rc-p66m-x6qq)

https://github.com/getgrav/grav-plugin-formAndy MillerApr 29, 2026via ghsa
3 files changed · +27 2
  • blueprints.yaml+1 1 modified
    @@ -1,7 +1,7 @@
     name: Form
     slug: form
     type: plugin
    -version: 9.0.3
    +version: 9.1.0
     description: Enables forms handling and processing
     icon: check-square
     author:
    
  • CHANGELOG.md+6 0 modified
    @@ -1,3 +1,9 @@
    +# v9.1.0
    +## 04/29/2026
    +
    +1. [](#bugfix)
    +   * [security] Fixed unauthenticated page-content overwrite via file upload (GHSA-w4rc-p66m-x6qq). Public form uploads now strip path components from the POST-supplied filename and hard-block page-content extensions (`md`, `yaml`, `yml`, `json`, `twig`, `ini`) regardless of the configurable dangerous-extensions list. A permissive `accept` policy combined with the default `destination: self@` could otherwise let an attacker overwrite the page's own `.md` and pivot to super-admin via a `process: save` action.
    +
     # v9.0.3
     ## 04/28/2026
     
    
  • classes/Form.php+20 1 modified
    @@ -580,7 +580,11 @@ public function uploadFiles()
             $grav->fireEvent('onFormUploadSettings', new Event(['settings' => &$settings, 'post' => $post]));
     
             $upload = json_decode(json_encode($this->normalizeFiles($_FILES['data'], $settings->name)), true);
    -        $filename = $post['filename'] ?? $upload['file']['name'];
    +        // Strip any path component from the POST-supplied filename. The admin
    +        // controllers already do this; the public form path historically did
    +        // not, which let an attacker collide the upload with files outside
    +        // the intended destination.
    +        $filename = Utils::basename((string) ($post['filename'] ?? $upload['file']['name']));
             $field = $upload['field'];
     
             // Handle errors and breaks without proceeding further
    @@ -605,6 +609,21 @@ public function uploadFiles()
                 ];
             }
     
    +        // Hard-block page-content extensions regardless of the configurable
    +        // dangerous-extensions list. With destination: self@ (the default),
    +        // an upload lands in the page directory, and a permissive accept
    +        // policy would otherwise let an unauthenticated user overwrite the
    +        // page's own .md/.yaml — turning a file upload into arbitrary
    +        // page-content takeover (GHSA-w4rc-p66m-x6qq).
    +        $extension = strtolower((string) pathinfo($filename, PATHINFO_EXTENSION));
    +        if (in_array($extension, ['md', 'yaml', 'yml', 'json', 'twig', 'ini'], true)) {
    +            return [
    +                'status'  => 'error',
    +                'message' => sprintf($language->translate('PLUGIN_FORM.FILEUPLOAD_UNABLE_TO_UPLOAD', null),
    +                    $filename, 'File type not allowed')
    +            ];
    +        }
    +
             if (!isset($settings->destination)) {
                 return [
                     'status'  => 'error',
    

Vulnerability mechanics

AI mechanics synthesis has not run for this CVE yet.

References

4

News mentions

0

No linked articles in our index yet.