Skip to main content
CVE Vulnerability Database
Vulnerability Database/CVE-2026-61607

CVE-2026-61607: Grav API Plugin XSS Vulnerability

CVE-2026-61607 is an XSS flaw in Grav API Plugin that allows attackers to upload malicious SVG files containing JavaScript. This post explains its impact, affected versions, and mitigation steps.

Updated:

CVE-2026-61607 Overview

CVE-2026-61607 is a stored cross-site scripting (XSS) vulnerability in the Grav API Plugin, a RESTful API extension for Grav CMS that provides headless access to site content. Versions prior to 1.0.2 fail to sanitize Scalable Vector Graphics (SVG) uploads in the POST /api/v1/media endpoint. The HandlesMediaUploads::processUploadedFile() function validates the SVG filename extension but does not call Security::sanitizeSVG(). An authenticated attacker with api.media.write permission can upload an SVG containing JavaScript. The server serves the file with Content-Type: image/svg+xml, causing the embedded script to execute in the victim's browser context. The issue is fixed in version 1.0.2.

Critical Impact

Authenticated attackers can steal session data and perform authenticated actions in the context of any user who opens the malicious SVG file.

Affected Products

  • Grav API Plugin versions prior to 1.0.2
  • Grav CMS deployments with the API plugin installed
  • Any Grav instance exposing POST /api/v1/media to users with api.media.write permission

Discovery Timeline

  • 2026-08-19 - CVE-2026-61607 published to the National Vulnerability Database (NVD)
  • 2026-08-19 - Last updated in NVD database

Technical Details for CVE-2026-61607

Vulnerability Analysis

The vulnerability is a stored cross-site scripting flaw [CWE-79] in the media upload pipeline of the Grav API Plugin. When a client sends a request to POST /api/v1/media, the plugin routes the file through HandlesMediaUploads::processUploadedFile(). This function checks that the uploaded file has a valid SVG extension but omits the sanitization step that strips executable content from SVG payloads.

Because SVG is an XML-based format that natively supports embedded <script> tags and event handlers, an attacker can craft an SVG containing arbitrary JavaScript. The Grav server subsequently serves the stored file with the image/svg+xml MIME type. Browsers interpret this response as active content and execute the embedded script in the origin of the Grav site.

Exploitation requires an authenticated account with api.media.write permission and a victim who opens or previews the uploaded file. Successful execution runs in the victim's session, enabling theft of session cookies, exfiltration of API tokens, and any authenticated action the victim can perform through the Grav interface.

Root Cause

The root cause is a missing call to Security::sanitizeSVG() in the upload handler. The patch in commit d25eedb imports Grav\Common\Security into both HandlesMediaUploads.php and BlueprintUploadController.php so that SVG contents can be sanitized before being written to disk.

Attack Vector

The attacker sends an HTTP POST request to /api/v1/media with a crafted SVG file containing a JavaScript payload inside a <script> element or an event handler attribute. Once stored, the file is served under its media URL as image/svg+xml, and any user who navigates to that URL triggers script execution in the Grav origin.

php
// Patch: classes/Api/Controllers/HandlesMediaUploads.php (v1.0.2)
 namespace Grav\Plugin\Api\Controllers;

+use Grav\Common\Security;
 use Grav\Plugin\Api\Exceptions\ValidationException;
 use Grav\Plugin\Api\Serializers\MediaSerializer;
 use Grav\Plugin\Api\Services\ThumbnailService;

// Patch: classes/Api/Controllers/BlueprintUploadController.php (v1.0.2)
 namespace Grav\Plugin\Api\Controllers;

 use Grav\Common\Filesystem\Folder;
+use Grav\Common\Security;
 use Grav\Plugin\Api\Exceptions\ForbiddenException;

Source: GitHub Commit d25eedb

Detection Methods for CVE-2026-61607

Indicators of Compromise

  • SVG files stored in Grav media directories containing <script> tags, javascript: URIs, or event handler attributes such as onload, onerror, or onclick.
  • HTTP POST requests to /api/v1/media originating from accounts with api.media.write permission that upload files with the .svg extension.
  • Web server responses returning stored SVG files with Content-Type: image/svg+xml from user-controlled upload paths.

Detection Strategies

  • Inspect all SVG files currently stored under Grav's user/pages and media directories for embedded JavaScript, foreign object elements, or external entity references.
  • Correlate API access logs against the Grav user database to identify accounts with api.media.write permission that recently uploaded SVG content.
  • Deploy web application firewall rules that scan multipart uploads to /api/v1/media for SVG payloads containing script tags or event handlers.

Monitoring Recommendations

  • Monitor outbound traffic from browsers that render Grav content for anomalous requests to attacker-controlled domains, which may indicate session token exfiltration.
  • Log and alert on new SVG uploads through the Grav API, including the uploading user, source IP, and file hash.
  • Track authentication events immediately following SVG media views to detect session hijacking or unauthorized administrative actions.

How to Mitigate CVE-2026-61607

Immediate Actions Required

  • Upgrade the Grav API Plugin to version 1.0.2 or later, which enforces Security::sanitizeSVG() on media uploads.
  • Audit existing SVG files in Grav media storage and remove or sanitize any files containing scripts or event handlers.
  • Review and restrict the api.media.write permission to trusted accounts only, and rotate credentials for any account suspected of misuse.

Patch Information

The fix is delivered in Grav API Plugin version 1.0.2, published in commit d25eedb84a387f2c71b12a374f2a4b3d74339a7e. The patch imports Grav\Common\Security into the upload controllers so that SVG contents are sanitized before being written. See the GitHub Release 1.0.2 and the GitHub Security Advisory GHSA-7vhm-8x52-2r5p for full release notes.

Workarounds

  • Disable SVG uploads at the web server or reverse proxy layer until the plugin can be upgraded.
  • Configure the web server to serve stored SVG files with Content-Type: text/plain or with Content-Disposition: attachment to prevent inline script execution.
  • Apply a Content Security Policy (CSP) that blocks inline script execution on pages that render user-uploaded media.
bash
# Nginx example: force SVG downloads instead of inline rendering
location ~* \.svg$ {
    add_header Content-Disposition "attachment";
    add_header X-Content-Type-Options "nosniff";
}

# Upgrade the Grav API Plugin via the Grav CLI
bin/gpm update api 1.0.2

Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

Default Legacy - Prefooter | Experience the World’s Most Advanced Cybersecurity Platform

Experience the Most Advanced Cybersecurity Platform

See how the world’s most intelligent, autonomous cybersecurity platform can protect your organization today and into the future.