TL;DR
I got CVE-2026-54717 in SilverStripe CMS.
This one was a stored XSS in the CMS admin interface, specifically in the page list view breadcrumbs.
The vulnerable area was:
/admin/pages/listviewAn attacker with permission to create or edit pages could place HTML or JavaScript in a parent page title or menu title, then get that payload rendered inside the breadcrumb trail for child pages.
So the bug was not in the current page title itself.
It was in the ancestor breadcrumb path.
The bug
The report path was pretty straightforward.
When the page list view was built, ancestor page titles were gathered and concatenated into a breadcrumb string:
$pages = $item->getAncestors();$pageNames = [];foreach ($pages as $page) { $pageNames[] = $page->MenuTitle ?: $page->Title;}$breadcrumbs = implode('/', $pageNames);
return $title . sprintf( '<p class="small cms-list__item-breadcrumbs">%s</p>', $breadcrumbs);That is the whole issue.
The current page title had already gone through the safer rendering path, but the ancestor titles used for the breadcrumb string were inserted into an HTML fragment without proper escaping first.
So if an attacker controlled one of those parent titles, the breadcrumb renderer would happily turn it back into live HTML in the CMS interface.
Why it worked
The attacker-controlled value could come from either:
MenuTitle- or fallback
Title
And because the breadcrumb string was built with implode('/') and then interpolated directly into:
<p class="small cms-list__item-breadcrumbs">%s</p>the output path treated the whole breadcrumb string as already-safe HTML.
That is exactly the kind of bug that feels small in code review until you remember that page titles are just user-controlled content with a nicer label.
Repro shape
The payload from the report was simple:
<img src=x onerror=alert(1)>The repro flow was:
- log in as a CMS user who can create or edit pages
- create or edit a parent page
- set
TitleorMenuTitleto the payload above - create a child page under that parent
- visit the list view for that parent
Example target:
/admin/pages/listview?ParentID=<parentID>At that point, the breadcrumb trail would render the attacker-controlled HTML and execute it in the CMS admin context.
Why I liked it
I like this kind of stored XSS because it hides in a UI detail that people tend to trust too much.
Breadcrumbs look decorative. They feel like a harmless secondary label.
But once that breadcrumb is built from page titles inside the authenticated CMS interface, it becomes a very real execution sink.
And the privilege boundary is good too:
- lower-privileged content editor controls page title
- higher-privileged CMS user opens the list view
- payload executes in the victim admin origin
That is a clean stored-XSS story.
Impact
The original report angle was the one I care about most here: editor-to-admin abuse inside the CMS.
Once JavaScript runs in that origin, the attacker can potentially:
- execute privileged CMS actions on behalf of the victim
- modify or publish content
- access same-origin admin data
- exfiltrate CSRF tokens
- forge follow-up requests
The public advisory ended up describing the impact more narrowly as:
Page breadcrumbs in the CMS are vulnerable to XSS when viewed using the page list view
That is still the same bug, just phrased more conservatively.
Public advisory status
The public GHSA now lists:
- CVE:
CVE-2026-54717 - Severity:
Moderate - CVSS:
5.4 - Vector:
CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:L/A:N - Affected: versions before
6.2.1 - Patched:
6.2.1
That is a bit more conservative than how I initially thought about the issue during reporting, but the underlying bug is still the same stored XSS in authenticated CMS workflow.
Fix direction
The fix direction is also the obvious one.
Any user-controlled value included in the breadcrumb output should be escaped before it is inserted into the HTML fragment.
In SilverStripe terms, that means using proper output encoding such as:
Convert::raw2xml()or the equivalent escaping path before rendering the breadcrumb string.
Reference