Fix stored XSS in “Save as HTML” exports by escaping templated fields#5808
Fix stored XSS in “Save as HTML” exports by escaping templated fields#5808Chaitu7032 wants to merge 4 commits intosugarlabs:masterfrom
Conversation
|
✅ All Jest tests passed! This PR is ready to merge. |
|
✅ All Jest tests passed! This PR is ready to merge. |
|
@walterbender sir .. I request to please have a look when you have time .. |
|
@Chaitu7032 @walterbender pr-5808.mp4 |
|
@Commanderk3 thanks for testing I will go through it, thankyou for taking look into it .. |
|
@Commanderk3 exported HTML stores project JSON as escaped text (e.g. "), so [JSON.parse()] was receiving strings like [[0,"star",...] and throwing [Unexpected token '&'] thanks for pointing it out .. iam giving fix for it .. |
No worries, but please do more testing from next time👍 |
|
✅ All Jest tests passed! This PR is ready to merge. |
|
✅ All Jest tests passed! This PR is ready to merge. |
video_20260220_165032_edit.mp4The import project crash is solved now .. @Commanderk3 . Thanks you so much I will make sure it will not happen in future . I apologise for this.. |
Summary
**This PR fixes a stored XSS vulnerability in the “Save as HTML” export feature.
Previously, user-controlled project fields (project name, description, exported data, and image URL) were inserted into an HTML template without escaping. A malicious project could inject markup or scripts that would execute when someone opened the exported
.htmlfile.The export path now safely escapes user-controlled values and sanitizes image URLs so exported HTML files cannot execute injected code. **
What was happening before
The HTML exporter builds a full document by taking a template string and directly replacing placeholders like:
{{ project_name }} {{ project_description }} {{ data }} {{ project_image }}Because these values were inserted without escaping, a crafted project name such as:
</title><img src=x onerror=alert(1)><title>could break out of the <title> element and inject a new tag with JavaScript execution.
Impact:
Anyone who receives and opens an exported .html file could have script executed in their browser.
This is especially risky because exporting and sharing projects is a normal workflow.
What this PR changes
The exporter now treats all user-controlled values as text, not HTML.
In
SaveInterface.js,prepareHTML()now:Escapes HTML special characters in:
(& < > " '→ escaped entities)Sanitizes the project image URL before inserting it:
- Allows
http://andhttps://- Allows
data:image/*;base64,...- Allows relative URLs
- Rejects other schemes (e.g.
javascript:)Uses function replacements (.replace(..., () => value)) so escaping is applied consistently to every placeholder occurrence.
Behavior after the fix
If a project name or description contains HTML (malicious or accidental), it is exported as visible text, not interpreted as markup.
Example repro payload:
</title><img src=x onerror=alert(1)><title>After the fix:
<img ...>({{ data }})is also rendered as text and cannot inject<script>tags.Tests / Verification
Added a regression test that uses the exact exploit payload and verifies it is escaped and not executable:
SaveInterface.test.js(XSS regression coverage)Verified locally with:
npx jest SaveInterface.test.js --runInBandHow to test manually
</title><img src=x onerror=alert(1)><title>Expected result:
(e.g. <img ...>)Security notes
Image URL sanitization further reduces risk from attribute injection and unsafe schemes.