Presentation
Grav is an open-source flat-file PHP content management system developed by Trilby Media. Its Form plugin is the official form builder: a form is declared in page frontmatter or in a blueprint as a list of fields, and each field type is rendered by its own Twig template shipped with the plugin.
HDW Sec found that two of those templates print option labels through the Twig |raw filter, so an author who controls a form’s option labels stores markup that executes in the browser of everyone who later views the form. The two sinks are siblings of a select option-text flaw that had already been reported and fixed, and that earlier fix did not cover them.
Issue(s)
- The option-rendering templates disagree on how they emit an option label. The
checkboxestemplate escapes it, whileradio(templates/forms/fields/radio/radio.html.twig:18) andtoggle(templates/forms/fields/toggle/toggle.html.twig:5and:49) pass it through|raw. - All three iterate the same
field.optionsstructure, so the same attacker-controlled value reaches an escaped sink in one template and an unescaped one in the other two. - The
selectvariant of this flaw was fixed in CVE-2026-42842. That fix dropped|rawfromselect.html.twigonly, leavingradioandtoggleexploitable: an incomplete fix rather than a new sink. - Reproduced live on Grav 2.0.12 with grav-plugin-form 9.1.14. A page defining
radio,toggleandcheckboxesfields whose option labels all carry the same<img src=x onerror=...>payload serves the radio and toggle labels as live elements, while the checkboxes label on the same page is escaped. That differential isolates the defect to the two templates. - The payload runs for front-end visitors of the public page and for any higher-privileged administrator who previews or opens it, which crosses the author to visitor and author to administrator trust boundary. Grav rated it moderate, 5.4.
- One honest limitation: in the lab the option labels came from page-author frontmatter, which is that author’s own input. A lower-privileged dynamic option provider feeding the same labels was not independently wired, so the demonstrated boundary is author to viewer rather than anonymous to author.
References
- GitHub advisory: GHSA-5xv4-g337-2pg7, published 2026-07-26.
- CVE-2026-72821, assigned 2026-08-14.
- Original, incompletely fixed advisory: CVE-2026-42842.
- Fixed in grav-plugin-form 9.1.15.