CVE-2026-42841
Grav: Stored XSS via Markdown media attribute() action in Grav CMS
Grav is a file-based Web platform. Prior to 2.0.0-beta.2, an authenticated user with page editing permissions can inject an executable JavaScript event-handler attribute into rendered image HTML through Grav's Markdown media action syntax. The issue is caused by Markdown image query parameters being converted into callable media actions. The public attribute() media method can be reached this way, allowing an editor to set an arbitrary HTML attribute name and value on the generated image element. 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
- High
- User interaction
- Passive
What an attacker can affect
- Confidentiality
- High
- Integrity
- Low
- Availability
- None
Exploit likelihood
What each source reports
CVE List Score used
6.9
Grav: Stored XSS via Markdown media attribute() action in Grav CMS
Grav is a file-based Web platform. Prior to 2.0.0-beta.2, an authenticated user with page editing permissions can inject an executable JavaScript event-handler attribute into rendered image HTML through Grav's Markdown media action syntax. The issue is caused by Markdown image query parameters being converted into callable media actions. The public attribute() media method can be reached this way, allowing an editor to set an arbitrary HTML attribute name and value on the generated image element. This vulnerability is fixed in 2.0.0-beta.2.
- Record
CVE-2026-42841- CVSS 4.0
- 6.9 Medium
CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:P/VC:H/VI:L/VA:N/SC:H/SI:L/SA:N - Weakness
- CWE-79
- Updated
- 2026-11-02
EUVDEUVD-2026-29072
6.9
Grav is a file-based Web platform. Prior to 2.0.0-beta.2, an authenticated user with page editing permissions can inject an executable JavaScript event-handler attribute into rendered image HTML through Grav's Markdown media action syntax. The issue is caused by Markdown image query parameters being converted into callable media actions. The public attribute() media method can be reached this way, allowing an editor to set an arbitrary HTML attribute name and value on the generated image element. This vulnerability is fixed in 2.0.0-beta.2.
- Record
EUVD-2026-29072- CVSS 4.0
- 6.9 Medium
CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:P/VC:H/VI:L/VA:N/SC:H/SI:L/SA:N - Updated
- 2026-11-02
GitHub AdvisoriesGHSA-r7fx-8g49-7hhr
6.9
Grav CMS vulnerable to stored XSS via Markdown media attribute() action
Summary
An authenticated user with page editing permissions can inject an executable JavaScript event-handler attribute into rendered image HTML through Grav's Markdown media action syntax.
The issue is caused by Markdown image query parameters being converted into callable media actions. The public attribute() media method can be reached this way, allowing an editor to set an arbitrary HTML attribute name and value on the generated image element.
For example, this Markdown:
)
is rendered as an image tag containing an executable onload handler:
<img onload="alert(document.domain)" alt="Quarterly market overview" src="/user/pages/03.campaigns/market-overview.gif?...">
This results in stored XSS when another user views the affected page. In a multi-user Grav installation, a lower-privileged page editor could use this to target administrators or reviewers who preview or view editor-controlled content.
Tested versions:
- Grav CMS: 1.7.49.5
- Admin Plugin: 1.10.49.1
Suggested classification:
- CWE-79: Improper Neutralization of Input During Web Page Generation
- Stored Cross-Site Scripting
- Suggested CVSS v4.0 score if page editing is considered high privilege: 6.9 Medium
- Suggested CVSS v4.0 vector:
CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:P/VC:H/VI:L/VA:N/SC:H/SI:L/SA:N - Suggested CVSS v3.1 score if page editing is considered high privilege: 6.9 Medium
- Suggested CVSS v3.1 vector:
CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:L/A:N
Details
The issue appears to come from this source-to-sink flow:
ParsedownGravTrait::inlineImage()processes Markdown images.Excerpts::processImageExcerpt()resolves the referenced media object.Excerpts::processMediaActions()parses the image URL query string into media actions.call_user_func_array()invokes the requested action method on the media object.MediaObjectTrait::attribute()stores the attacker-controlled attribute name and value.- The media object returns a Parsedown element containing the injected attribute.
- Parsedown renders the attribute name into the final HTML.
Relevant code paths:
system/src/Grav/Common/Markdown/ParsedownGravTrait.php
system/src/Grav/Common/Page/Markdown/Excerpts.php
system/src/Grav/Common/Media/Traits/MediaObjectTrait.php
system/src/Grav/Common/Page/Medium/StaticImageMedium.php
system/src/Grav/Common/Page/Medium/ImageMedium.php
vendor/erusev/parsedown/Parsedown.php
In system/src/Grav/Common/Markdown/ParsedownGravTrait.php, Markdown image excerpts are passed into Grav-specific media handling:
if (isset($excerpt['element']['attributes']['src'])) {
$excerpt = $this->excerpts->processImageExcerpt($excerpt);
}
In system/src/Grav/Common/Page/Markdown/Excerpts.php, query string parameters are converted into media action calls. The query parameter name becomes the method name:
$carry[] = ['method' => $parts[0], 'params' => $value];
The requested method is later invoked dynamically:
$medium = call_user_func_array([$medium, $action['method']], $args);
For the payload:
attribute=onload,alert(document.domain)
the method is attribute, and the arguments are onload and alert(document.domain).
In system/src/Grav/Common/Media/Traits/MediaObjectTrait.php, attribute() stores the caller-controlled attribute name directly:
public function attribute($attribute = null, $value = '')
{
if (!empty($attribute)) {
$this->attributes[$attribute] = $value;
}
return $this;
}
The image media classes then return the collected attributes as attributes for an img element.
In system/src/Grav/Common/Page/Medium/StaticImageMedium.php:
return ['name' => 'img', 'attributes' => $attributes];
The non-static image path in system/src/Grav/Common/Page/Medium/ImageMedium.php also returns image attributes in the…
- Record
GHSA-r7fx-8g49-7hhr- CVSS 4.0
- 6.9 Medium
CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:P/VC:H/VI:L/VA:N/SC:H/SI:L/SA:N - CVSS 3.1
- 4.8 Medium
CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-79
- Updated
- 2026-11-02
NVD
6.9
Grav is a file-based Web platform. Prior to 2.0.0-beta.2, an authenticated user with page editing permissions can inject an executable JavaScript event-handler attribute into rendered image HTML through Grav's Markdown media action syntax. The issue is caused by Markdown image query parameters being converted into callable media actions. The public attribute() media method can be reached this way, allowing an editor to set an arbitrary HTML attribute name and value on the generated image element. This vulnerability is fixed in 2.0.0-beta.2.
- Record
CVE-2026-42841- CVSS 4.0
- 6.9 Medium
CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:P/VC:H/VI:L/VA:N/SC:H/SI:L/SA:N/E:X/CR:X/IR:X/AR:X/MAV:X/MAC:X/MAT:X/MPR:X/MUI:X/MVC:X/MVI:X/MVA:X/MSC:X/MSI:X/MSA:X/S:X/AU:X/R:X/V:X/RE:X/U:X - CVSS 3.1
- 4.8 Medium
CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-79
- Updated
- 2026-11-02
OSV
6.9
Grav: Stored XSS via Markdown media attribute() action in Grav CMS
Grav is a file-based Web platform. Prior to 2.0.0-beta.2, an authenticated user with page editing permissions can inject an executable JavaScript event-handler attribute into rendered image HTML through Grav's Markdown media action syntax. The issue is caused by Markdown image query parameters being converted into callable media actions. The public attribute() media method can be reached this way, allowing an editor to set an arbitrary HTML attribute name and value on the generated image element. This vulnerability is fixed in 2.0.0-beta.2.
- Record
CVE-2026-42841- CVSS 4.0
- 6.9 Medium
CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:P/VC:H/VI:L/VA:N/SC:H/SI:L/SA:N - Weakness
- CWE-79
- Updated
- 2026-11-02
OSVGHSA-r7fx-8g49-7hhr
6.9
Grav CMS vulnerable to stored XSS via Markdown media attribute() action
Summary
An authenticated user with page editing permissions can inject an executable JavaScript event-handler attribute into rendered image HTML through Grav's Markdown media action syntax.
The issue is caused by Markdown image query parameters being converted into callable media actions. The public attribute() media method can be reached this way, allowing an editor to set an arbitrary HTML attribute name and value on the generated image element.
For example, this Markdown:
)
is rendered as an image tag containing an executable onload handler:
<img onload="alert(document.domain)" alt="Quarterly market overview" src="/user/pages/03.campaigns/market-overview.gif?...">
This results in stored XSS when another user views the affected page. In a multi-user Grav installation, a lower-privileged page editor could use this to target administrators or reviewers who preview or view editor-controlled content.
Tested versions:
- Grav CMS: 1.7.49.5
- Admin Plugin: 1.10.49.1
Suggested classification:
- CWE-79: Improper Neutralization of Input During Web Page Generation
- Stored Cross-Site Scripting
- Suggested CVSS v4.0 score if page editing is considered high privilege: 6.9 Medium
- Suggested CVSS v4.0 vector:
CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:P/VC:H/VI:L/VA:N/SC:H/SI:L/SA:N - Suggested CVSS v3.1 score if page editing is considered high privilege: 6.9 Medium
- Suggested CVSS v3.1 vector:
CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:H/I:L/A:N
Details
The issue appears to come from this source-to-sink flow:
ParsedownGravTrait::inlineImage()processes Markdown images.Excerpts::processImageExcerpt()resolves the referenced media object.Excerpts::processMediaActions()parses the image URL query string into media actions.call_user_func_array()invokes the requested action method on the media object.MediaObjectTrait::attribute()stores the attacker-controlled attribute name and value.- The media object returns a Parsedown element containing the injected attribute.
- Parsedown renders the attribute name into the final HTML.
Relevant code paths:
system/src/Grav/Common/Markdown/ParsedownGravTrait.php
system/src/Grav/Common/Page/Markdown/Excerpts.php
system/src/Grav/Common/Media/Traits/MediaObjectTrait.php
system/src/Grav/Common/Page/Medium/StaticImageMedium.php
system/src/Grav/Common/Page/Medium/ImageMedium.php
vendor/erusev/parsedown/Parsedown.php
In system/src/Grav/Common/Markdown/ParsedownGravTrait.php, Markdown image excerpts are passed into Grav-specific media handling:
if (isset($excerpt['element']['attributes']['src'])) {
$excerpt = $this->excerpts->processImageExcerpt($excerpt);
}
In system/src/Grav/Common/Page/Markdown/Excerpts.php, query string parameters are converted into media action calls. The query parameter name becomes the method name:
$carry[] = ['method' => $parts[0], 'params' => $value];
The requested method is later invoked dynamically:
$medium = call_user_func_array([$medium, $action['method']], $args);
For the payload:
attribute=onload,alert(document.domain)
the method is attribute, and the arguments are onload and alert(document.domain).
In system/src/Grav/Common/Media/Traits/MediaObjectTrait.php, attribute() stores the caller-controlled attribute name directly:
public function attribute($attribute = null, $value = '')
{
if (!empty($attribute)) {
$this->attributes[$attribute] = $value;
}
return $this;
}
The image media classes then return the collected attributes as attributes for an img element.
In system/src/Grav/Common/Page/Medium/StaticImageMedium.php:
return ['name' => 'img', 'attributes' => $attributes];
The non-static image path in system/src/Grav/Common/Page/Medium/ImageMedium.php also returns image attributes in the…
- Record
GHSA-r7fx-8g49-7hhr- CVSS 4.0
- 6.9 Medium
CVSS:4.0/AV:N/AC:L/AT:P/PR:H/UI:P/VC:H/VI:L/VA:N/SC:H/SI:L/SA:N - CVSS 3.1
- 4.8 Medium
CVSS:3.1/AV:N/AC:L/PR:H/UI:R/S:C/C:L/I:L/A:N - Weakness
- CWE-79
- Updated
- 2026-11-02
Affected products
Affected packages
| Package | Affected | Fixed |
|---|---|---|
getgrav/gravPackagist |
before 2.0.0-beta.2 | 2.0.0-beta.2 |
getgrav/gravPackagist |
before 2.0.0-beta.2, plus listed versions 0.8.00.9.00.9.10.9.100.9.11 Show 45 moreShow less0.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 |
History
| Recorded | Changed | Sources |
|---|---|---|
| first indexed | CVE List, EUVD, GitHub Advisories, NVD, OSV |
Dates are when Every CVE recorded each change. Upstream dates may differ.
In short
CVE-2026-42841 is a medium vulnerability (CVSS 6.9) in Getgrav Grav, published May 5, 2026. No source lists public exploit code. EPSS puts the chance of exploitation in the next 30 days at 0.42%, the 36th percentile. Fixed in getgrav/grav 2.0.0-beta.2.
References
github.com/getgrav/grav/security/advisories/GHSA-r7fx-8g49-7hhr
github.com/getgrav/grav/commit/5a12f9be8314682c8713e569e330f11805d0a663
nvd.nist.gov/vuln/detail/CVE-2026-42841
github.com/advisories/GHSA-r7fx-8g49-7hhr
github.com/CVEProject/cvelistV5/tree/main/cves/2026/42xxx/CVE-2026-42841.json
github.com/getgrav/grav
Left out here: 271 versions and the rest of 2 source descriptions. The JSON record has them.