GHSA-w2x5-gv52-9ccv: XSS

Published Aug 24, 2026
·
Updated

Summary

The Sakai Conversations tool stores topic and post messages without HTML sanitization, and the frontend renders them using LitElement's unsafeHTML() directive, resulting in stored cross-site scripting (XSS). Any authenticated user with access to a site that has the Conversations tool enabled can inject arbitrary HTML and JavaScript that executes in the browsers of all other users who view that topic or post.

Description

The Conversations REST API endpoint POST /api/sites/{siteId}/topics accepts a message field in the JSON request body. The service layer (ConversationsServiceImpl) stores the message directly to the database (convtopics.MESSAGE) without invoking FormattedText.processFormattedText() or any equivalent HTML sanitizer.

The same issue affects post replies via POST /api/sites/{siteId}/topics/{topicId}/posts and comments stored in convcomments.

On the frontend, SakaiTopic.js, SakaiPost.js, and SakaiComment.js all render the message field using LitElement's unsafeHTML() directive:

- SakaiPost.js lines 429, 432: ${unsafeHTML(this.post.message)} - SakaiTopic.js line 679: ${unsafeHTML(this.topic.message)} - SakaiComment.js line 148: ${unsafeHTML(this.comment.message)}

Unlike other Sakai tools (Announcements, Assignments, Resources) which call FormattedText.processFormattedText() before persisting user content, the Conversations implementation has no equivalent protection at storage time or render time.

Proof of Concept

Setup: Admin/instructor session on a site with the Conversations tool enabled (siteId BELP275K7418).

Step 1 - Inject XSS payload in topic:

POST /api/sites/BELP275K7418/topics HTTP/1.1 Host: localhost:9107 Cookie: SAKAIID=<authenticated-session> Content-Type: application/json

{"title":"XSS Test Topic","message":"<img src=x onerror=alert(1)>","type":"QUESTION","visibility":"SITE","draft":false}

Response: HTTP 200, "message":"<img src=x onerror=alert(1)>" - raw HTML stored.

Step 2 - Verify stored in database:

sql SELECT TOPICID, TITLE, MESSAGE FROM convtopics WHERE TOPICID='e4c599c2-bd32-4364-9cbd-a5c9c102edfb'; -- Result: MESSAGE = <img src=x onerror=alert(1)>

Step 3 - Inject XSS payload in post reply:

POST /api/sites/BELP275K7418/topics/e4c599c2-bd32-4364-9cbd-a5c9c102edfb/posts HTTP/1.1 Host: localhost:9107 Cookie: SAKAIID=<authenticated-session> Content-Type: application/json

{"message":"<script>alert(document.cookie)<\/script>","siteId":"BELP275K7418"}

Response: HTTP 200, "message":"<script>alert(document.cookie)</script>" - raw script stored.

Step 4 - Verify in database:

sql SELECT POSTID, MESSAGE FROM convposts WHERE POSTID='e3cf7aed-c630-448a-89bb-27a8baacd269'; -- Result: MESSAGE = <script>alert(document.cookie)</script>

When any site member loads the Conversations view, the LitElement web component fetches the stored messages via the REST API and renders them with unsafeHTML(), causing the injected scripts and event handlers to execute.

Impact

An attacker with any site membership (student role or higher) can: - Perform actions on behalf of victims - Exfiltrate gradebook data and course content - In a university context with hundreds of students per course, a single malicious post can compromise all enrolled students simultaneously

Status / timeline: - 2026-06-02: Fix committed to master (2696b4b48cbef2e81512f52f84f7477adff78b27) - Release pending.

Affected Software

3 affected components
maven/org.sakaiproject.rubrics:rubrics-impl>=23.0<=23.3
maven/org.sakaiproject.kernel:sakai-kernel-impl>=23.0<=23.3
maven/org.sakaiproject.conversations:sakai-conversations-impl>=23.0<=23.3

Remediation

Recommended actions to resolve this vulnerability, in priority order.

  1. Upgrade

    Upgrade Sakai Conversations tool (SakaiTopic.js, SakaiPost.js, SakaiComment.js / ConversationsServiceImpl) to a version that resolves this vulnerability.

    Patch 2696b4b48cbef2e81512f52f84f7477adff78b27
  2. Configuration

    Remove usage of LitElement's unsafeHTML() for Conversations message rendering (SakaiTopic.js line 679, SakaiPost.js lines 429 and 432, SakaiComment.js line 148) and render message content using an HTML sanitizer/safer rendering path so injected HTML/JS is not executed.

    Frontend (LitElement web components: SakaiTopic.js / SakaiPost.js / SakaiComment.js) Rendering of message field (LitElement unsafeHTML) = Replace unsafeHTML(this.topic.message / this.post.message / this.comment.message) with sanitized HTML rendering
  3. Configuration

    Update ConversationsServiceImpl so that message content is sanitized before persistence (currently stored directly into database fields like conv_topics.MESSAGE without calling FormattedText.processFormattedText() or equivalent HTML sanitizer).

    Backend service (ConversationsServiceImpl) Message persistence sanitization = Apply HTML sanitization before storing to conv_topics.MESSAGE/conv_posts.MESSAGE/conv_comments.MESSAGE

Event History

Aug 24, 2026
Advisory Published
via GitHub·07:37 PM
Data Sourced
via GitHub·07:37 PM
DescriptionSeverityWeaknessAffected Software

Frequently Asked Questions

1

Who can exploit this issue, and who is exposed to the payload?

An authenticated user who can access a site with the Conversations tool enabled can submit malicious content. The payload executes in the browsers of other users who view the affected topic, post, or comment.

2

What attacker access and interaction are required?

The attacker needs authenticated access to an affected site and must be able to create a topic, reply, or comment through the Conversations API. A victim must view the stored content for the JavaScript to execute.

3

Which API operations and stored content should be reviewed?

Review topic creation through POST /api/sites/{siteId}/topics and post creation through POST /api/sites/{siteId}/topics/{topicId}/posts. The affected message content is stored in conv_topics.MESSAGE, and the issue also affects replies and comments stored in conv_comments.

4

Can existing stored content remain dangerous after remediation?

Yes. Because the vulnerable behavior stores message fields directly and later renders them with unsafeHTML(), previously submitted malicious topics, posts, or comments may execute when viewed. Review existing Conversations content for untrusted HTML or JavaScript.

Contact

SecAlerts Pty Ltd.
132 Wickham Terrace
Fortitude Valley,
QLD 4006, Australia
info@secalerts.co
By using SecAlerts services, you agree to our services end-user license agreement. This website is safeguarded by reCAPTCHA and governed by the Google Privacy Policy and Terms of Service. All names, logos, and brands of products are owned by their respective owners, and any usage of these names, logos, and brands for identification purposes only does not imply endorsement. If you possess any content that requires removal, please get in touch with us.
© 2026 SecAlerts Pty Ltd.
ABN: 70 645 966 203, ACN: 645 966 203