XWiki Platform vulnerable to Cross-site Scripting through attachment filename in uploader
Description
XWiki Platform is a generic wiki platform offering runtime services for applications built on top of it. When uploading an attachment with a malicious filename, malicious JavaScript code could be executed. This requires a social engineering attack to get the victim into uploading a file with a malicious name. The malicious code is solely executed during the upload and affects only the user uploading the attachment. While this allows performing actions in the name of that user, it seems unlikely that a user wouldn't notice the malicious filename while uploading the attachment. This has been patched in XWiki 14.10.21, 15.5.5, 15.10.6 and 16.0.0.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
org.xwiki.platform:xwiki-platform-web-warMaven | >= 4.2-milestone-3, < 14.10.21 | 14.10.21 |
org.xwiki.platform:xwiki-platform-web-warMaven | >= 15.0-rc-1, < 15.5.5 | 15.5.5 |
org.xwiki.platform:xwiki-platform-web-warMaven | >= 15.6-rc-1, < 15.10.6 | 15.10.6 |
org.xwiki.platform:xwiki-platform-web-warMaven | >= 16.0.0-rc-1, < 16.0.0 | 16.0.0 |
Affected products
1- Range: >= 4.2-milestone-3, < 14.10.21
Patches
4910a5018a500XWIKI-19611: Improve filename escaping in attachment upload
3 files changed · +26 −5
xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/it/org/xwiki/flamingo/test/docker/AttachmentIT.java+19 −0 modified@@ -65,6 +65,8 @@ class AttachmentIT private static final String SECOND_ATTACHMENT = "SmallAttachment2.txt"; + private static final String ESCAPED_ATTACHMENT = "<strong>EscapedAttachment.txt"; + private static final String IMAGE_ATTACHMENT = "image.gif"; private static final String SMALL_SIZE_ATTACHMENT = "SmallSizeAttachment.png"; @@ -441,6 +443,23 @@ void deleteAttachmentWithSpecialChar(TestUtils setup, TestReference testReferenc basePage.getXWikiMessageContent()); } + @Test + @Order(9) + void checkEscapingInAttachmentName(TestUtils setup, TestReference testReference, + TestConfiguration testConfiguration) + { + setup.loginAsSuperAdmin(); + setup.createPage(testReference, "Empty content"); + AttachmentsPane attachmentsPane = new AttachmentsViewPage().openAttachmentsDocExtraPane(); + + attachmentsPane.setFileToUpload(getFileToUpload(testConfiguration, ESCAPED_ATTACHMENT).getAbsolutePath()); + attachmentsPane.waitForUploadToFinish(ESCAPED_ATTACHMENT); + attachmentsPane.clickHideProgress(); + + assertTrue(attachmentsPane.attachmentExistsByFileName(ESCAPED_ATTACHMENT)); + attachmentsPane.deleteAttachmentByFileByName(ESCAPED_ATTACHMENT); + } + private String getAttachmentsMacroContent(DocumentReference docRef) { StringBuilder sb = new StringBuilder();
xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/resources/AttachmentIT/<strong>EscapedAttachment.txt+1 −0 added@@ -0,0 +1 @@ +This is an attachment whose name should be escaped. \ No newline at end of file
xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/uicomponents/widgets/upload.js+6 −5 modified@@ -124,7 +124,7 @@ var XWiki = (function(XWiki) { if (this.options.enableFileInfo) { statusUI.FILE_INFO = UploadUtils.createDiv('file-info'); - (statusUI.FILE_NAME = UploadUtils.createSpan('file-name', this.file.name)).title = this.file.type; + (statusUI.FILE_NAME = UploadUtils.createSpan('file-name', this.file.name.escapeHTML())).title = this.file.type; statusUI.FILE_SIZE = UploadUtils.createSpan('file-size', ' (' + UploadUtils.bytesToSize(this.file.size) + ')'); statusUI.FILE_CANCEL = UploadUtils.createButton("$services.localization.render('core.widgets.html5upload.item.cancel')", this.cancelUpload.bindAsEventListener(this)); // TODO MIME type icon? @@ -295,7 +295,7 @@ var XWiki = (function(XWiki) { this.statusUI.FILE_CANCEL.addClassName('hidden'); } this.formData.input.fire('xwiki:html5upload:message', {content: 'UPLOAD_FINISHING', type: 'inprogress', source: this, - parameters : {name : this.file.name} + parameters : {name : this.file.name.escapeHTML()} }); }, @@ -324,7 +324,7 @@ var XWiki = (function(XWiki) { } } this.formData.input.fire('xwiki:html5upload:message', {content: 'UPLOAD_FINISHED', type: 'done', source: this, - parameters : {name : this.file.name, size : UploadUtils.bytesToSize(this.file.size)} + parameters : {name : this.file.name.escapeHTML(), size : UploadUtils.bytesToSize(this.file.size)} }); this.formData.input.fire('xwiki:html5upload:fileFinished', {source: this}); clearInterval(this.timer); @@ -354,7 +354,8 @@ var XWiki = (function(XWiki) { */ abnormalUploadFinish : function (message) { clearInterval(this.timer); - this.formData.input.fire('xwiki:html5upload:message', {content: message, type: 'error', source: this, parameters : {name : this.file.name}}); + this.formData.input.fire('xwiki:html5upload:message', {content: message, type: 'error', source: this, parameters : + {name : this.file.name.escapeHTML()}}); this.formData.input.fire('xwiki:html5upload:fileFinished', {source: this}); } }); @@ -517,7 +518,7 @@ var XWiki = (function(XWiki) { } } catch (ex) { this.showMessage(ex, 'error', {size : UploadUtils.bytesToSize(this.options && this.options.maxFilesize), - name : file.name, type: file.type + name : file.name.escapeHTML(), type: file.type }); } }
8b8a2d80529bXWIKI-19611: Improve filename escaping in attachment upload
3 files changed · +26 −5
xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/it/org/xwiki/flamingo/test/docker/AttachmentIT.java+19 −0 modified@@ -65,6 +65,8 @@ class AttachmentIT private static final String SECOND_ATTACHMENT = "SmallAttachment2.txt"; + private static final String ESCAPED_ATTACHMENT = "<strong>EscapedAttachment.txt"; + private static final String IMAGE_ATTACHMENT = "image.gif"; private static final String SMALL_SIZE_ATTACHMENT = "SmallSizeAttachment.png"; @@ -441,6 +443,23 @@ void deleteAttachmentWithSpecialChar(TestUtils setup, TestReference testReferenc basePage.getXWikiMessageContent()); } + @Test + @Order(9) + void checkEscapingInAttachmentName(TestUtils setup, TestReference testReference, + TestConfiguration testConfiguration) + { + setup.loginAsSuperAdmin(); + setup.createPage(testReference, "Empty content"); + AttachmentsPane attachmentsPane = new AttachmentsViewPage().openAttachmentsDocExtraPane(); + + attachmentsPane.setFileToUpload(getFileToUpload(testConfiguration, ESCAPED_ATTACHMENT).getAbsolutePath()); + attachmentsPane.waitForUploadToFinish(ESCAPED_ATTACHMENT); + attachmentsPane.clickHideProgress(); + + assertTrue(attachmentsPane.attachmentExistsByFileName(ESCAPED_ATTACHMENT)); + attachmentsPane.deleteAttachmentByFileByName(ESCAPED_ATTACHMENT); + } + private String getAttachmentsMacroContent(DocumentReference docRef) { StringBuilder sb = new StringBuilder();
xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/resources/AttachmentIT/<strong>EscapedAttachment.txt+1 −0 added@@ -0,0 +1 @@ +This is an attachment whose name should be escaped. \ No newline at end of file
xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/uicomponents/widgets/upload.js+6 −5 modified@@ -124,7 +124,7 @@ var XWiki = (function(XWiki) { if (this.options.enableFileInfo) { statusUI.FILE_INFO = UploadUtils.createDiv('file-info'); - (statusUI.FILE_NAME = UploadUtils.createSpan('file-name', this.file.name)).title = this.file.type; + (statusUI.FILE_NAME = UploadUtils.createSpan('file-name', this.file.name.escapeHTML())).title = this.file.type; statusUI.FILE_SIZE = UploadUtils.createSpan('file-size', ' (' + UploadUtils.bytesToSize(this.file.size) + ')'); statusUI.FILE_CANCEL = UploadUtils.createButton("$services.localization.render('core.widgets.html5upload.item.cancel')", this.cancelUpload.bindAsEventListener(this)); // TODO MIME type icon? @@ -295,7 +295,7 @@ var XWiki = (function(XWiki) { this.statusUI.FILE_CANCEL.addClassName('hidden'); } this.formData.input.fire('xwiki:html5upload:message', {content: 'UPLOAD_FINISHING', type: 'inprogress', source: this, - parameters : {name : this.file.name} + parameters : {name : this.file.name.escapeHTML()} }); }, @@ -324,7 +324,7 @@ var XWiki = (function(XWiki) { } } this.formData.input.fire('xwiki:html5upload:message', {content: 'UPLOAD_FINISHED', type: 'done', source: this, - parameters : {name : this.file.name, size : UploadUtils.bytesToSize(this.file.size)} + parameters : {name : this.file.name.escapeHTML(), size : UploadUtils.bytesToSize(this.file.size)} }); this.formData.input.fire('xwiki:html5upload:fileFinished', {source: this}); clearInterval(this.timer); @@ -354,7 +354,8 @@ var XWiki = (function(XWiki) { */ abnormalUploadFinish : function (message) { clearInterval(this.timer); - this.formData.input.fire('xwiki:html5upload:message', {content: message, type: 'error', source: this, parameters : {name : this.file.name}}); + this.formData.input.fire('xwiki:html5upload:message', {content: message, type: 'error', source: this, parameters : + {name : this.file.name.escapeHTML()}}); this.formData.input.fire('xwiki:html5upload:fileFinished', {source: this}); } }); @@ -517,7 +518,7 @@ var XWiki = (function(XWiki) { } } catch (ex) { this.showMessage(ex, 'error', {size : UploadUtils.bytesToSize(this.options && this.options.maxFilesize), - name : file.name, type: file.type + name : file.name.escapeHTML(), type: file.type }); } }
9df46f8e5313XWIKI-19611: Improve filename escaping in attachment upload
3 files changed · +26 −5
xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/it/org/xwiki/flamingo/test/docker/AttachmentIT.java+19 −0 modified@@ -65,6 +65,8 @@ class AttachmentIT private static final String SECOND_ATTACHMENT = "SmallAttachment2.txt"; + private static final String ESCAPED_ATTACHMENT = "<strong>EscapedAttachment.txt"; + private static final String IMAGE_ATTACHMENT = "image.gif"; private static final String SMALL_SIZE_ATTACHMENT = "SmallSizeAttachment.png"; @@ -446,6 +448,23 @@ void deleteAttachmentWithSpecialChar(TestUtils setup, TestReference testReferenc basePage.getXWikiMessageContent()); } + @Test + @Order(9) + void checkEscapingInAttachmentName(TestUtils setup, TestReference testReference, + TestConfiguration testConfiguration) + { + setup.loginAsSuperAdmin(); + setup.createPage(testReference, "Empty content"); + AttachmentsPane attachmentsPane = new AttachmentsViewPage().openAttachmentsDocExtraPane(); + + attachmentsPane.setFileToUpload(getFileToUpload(testConfiguration, ESCAPED_ATTACHMENT).getAbsolutePath()); + attachmentsPane.waitForUploadToFinish(ESCAPED_ATTACHMENT); + attachmentsPane.clickHideProgress(); + + assertTrue(attachmentsPane.attachmentExistsByFileName(ESCAPED_ATTACHMENT)); + attachmentsPane.deleteAttachmentByFileByName(ESCAPED_ATTACHMENT); + } + private String getAttachmentsMacroContent(DocumentReference docRef) { StringBuilder sb = new StringBuilder();
xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/resources/AttachmentIT/<strong>EscapedAttachment.txt+1 −0 added@@ -0,0 +1 @@ +This is an attachment whose name should be escaped. \ No newline at end of file
xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/uicomponents/widgets/upload.js+6 −5 modified@@ -124,7 +124,7 @@ var XWiki = (function(XWiki) { if (this.options.enableFileInfo) { statusUI.FILE_INFO = UploadUtils.createDiv('file-info'); - (statusUI.FILE_NAME = UploadUtils.createSpan('file-name', this.file.name)).title = this.file.type; + (statusUI.FILE_NAME = UploadUtils.createSpan('file-name', this.file.name.escapeHTML())).title = this.file.type; statusUI.FILE_SIZE = UploadUtils.createSpan('file-size', ' (' + UploadUtils.bytesToSize(this.file.size) + ')'); statusUI.FILE_CANCEL = UploadUtils.createButton("$services.localization.render('core.widgets.html5upload.item.cancel')", this.cancelUpload.bindAsEventListener(this)); // TODO MIME type icon? @@ -295,7 +295,7 @@ var XWiki = (function(XWiki) { this.statusUI.FILE_CANCEL.addClassName('hidden'); } this.formData.input.fire('xwiki:html5upload:message', {content: 'UPLOAD_FINISHING', type: 'inprogress', source: this, - parameters : {name : this.file.name} + parameters : {name : this.file.name.escapeHTML()} }); }, @@ -324,7 +324,7 @@ var XWiki = (function(XWiki) { } } this.formData.input.fire('xwiki:html5upload:message', {content: 'UPLOAD_FINISHED', type: 'done', source: this, - parameters : {name : this.file.name, size : UploadUtils.bytesToSize(this.file.size)} + parameters : {name : this.file.name.escapeHTML(), size : UploadUtils.bytesToSize(this.file.size)} }); this.formData.input.fire('xwiki:html5upload:fileFinished', {source: this}); clearInterval(this.timer); @@ -354,7 +354,8 @@ var XWiki = (function(XWiki) { */ abnormalUploadFinish : function (message) { clearInterval(this.timer); - this.formData.input.fire('xwiki:html5upload:message', {content: message, type: 'error', source: this, parameters : {name : this.file.name}}); + this.formData.input.fire('xwiki:html5upload:message', {content: message, type: 'error', source: this, parameters : + {name : this.file.name.escapeHTML()}}); this.formData.input.fire('xwiki:html5upload:fileFinished', {source: this}); } }); @@ -517,7 +518,7 @@ var XWiki = (function(XWiki) { } } catch (ex) { this.showMessage(ex, 'error', {size : UploadUtils.bytesToSize(this.options && this.options.maxFilesize), - name : file.name, type: file.type + name : file.name.escapeHTML(), type: file.type }); } }
6cdd69d31d6bXWIKI-19611: Improve filename escaping in attachment upload
3 files changed · +26 −5
xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/it/org/xwiki/flamingo/test/docker/AttachmentIT.java+19 −0 modified@@ -65,6 +65,8 @@ class AttachmentIT private static final String SECOND_ATTACHMENT = "SmallAttachment2.txt"; + private static final String ESCAPED_ATTACHMENT = "<strong>EscapedAttachment.txt"; + private static final String IMAGE_ATTACHMENT = "image.gif"; private static final String SMALL_SIZE_ATTACHMENT = "SmallSizeAttachment.png"; @@ -447,6 +449,23 @@ void deleteAttachmentWithSpecialChar(TestUtils setup, TestReference testReferenc basePage.getXWikiMessageContent()); } + @Test + @Order(9) + void checkEscapingInAttachmentName(TestUtils setup, TestReference testReference, + TestConfiguration testConfiguration) + { + setup.loginAsSuperAdmin(); + setup.createPage(testReference, "Empty content"); + AttachmentsPane attachmentsPane = new AttachmentsViewPage().openAttachmentsDocExtraPane(); + + attachmentsPane.setFileToUpload(getFileToUpload(testConfiguration, ESCAPED_ATTACHMENT).getAbsolutePath()); + attachmentsPane.waitForUploadToFinish(ESCAPED_ATTACHMENT); + attachmentsPane.clickHideProgress(); + + assertTrue(attachmentsPane.attachmentExistsByFileName(ESCAPED_ATTACHMENT)); + attachmentsPane.deleteAttachmentByFileByName(ESCAPED_ATTACHMENT); + } + private String getAttachmentsMacroContent(DocumentReference docRef) { StringBuilder sb = new StringBuilder();
xwiki-platform-core/xwiki-platform-flamingo/xwiki-platform-flamingo-skin/xwiki-platform-flamingo-skin-test/xwiki-platform-flamingo-skin-test-docker/src/test/resources/AttachmentIT/<strong>EscapedAttachment.txt+1 −0 added@@ -0,0 +1 @@ +This is an attachment whose name should be escaped. \ No newline at end of file
xwiki-platform-core/xwiki-platform-web/xwiki-platform-web-war/src/main/webapp/resources/uicomponents/widgets/upload.js+6 −5 modified@@ -124,7 +124,7 @@ var XWiki = (function(XWiki) { if (this.options.enableFileInfo) { statusUI.FILE_INFO = UploadUtils.createDiv('file-info'); - (statusUI.FILE_NAME = UploadUtils.createSpan('file-name', this.file.name)).title = this.file.type; + (statusUI.FILE_NAME = UploadUtils.createSpan('file-name', this.file.name.escapeHTML())).title = this.file.type; statusUI.FILE_SIZE = UploadUtils.createSpan('file-size', ' (' + UploadUtils.bytesToSize(this.file.size) + ')'); statusUI.FILE_CANCEL = UploadUtils.createButton("$services.localization.render('core.widgets.html5upload.item.cancel')", this.cancelUpload.bindAsEventListener(this)); // TODO MIME type icon? @@ -295,7 +295,7 @@ var XWiki = (function(XWiki) { this.statusUI.FILE_CANCEL.addClassName('hidden'); } this.formData.input.fire('xwiki:html5upload:message', {content: 'UPLOAD_FINISHING', type: 'inprogress', source: this, - parameters : {name : this.file.name} + parameters : {name : this.file.name.escapeHTML()} }); }, @@ -324,7 +324,7 @@ var XWiki = (function(XWiki) { } } this.formData.input.fire('xwiki:html5upload:message', {content: 'UPLOAD_FINISHED', type: 'done', source: this, - parameters : {name : this.file.name, size : UploadUtils.bytesToSize(this.file.size)} + parameters : {name : this.file.name.escapeHTML(), size : UploadUtils.bytesToSize(this.file.size)} }); this.formData.input.fire('xwiki:html5upload:fileFinished', {source: this}); clearInterval(this.timer); @@ -354,7 +354,8 @@ var XWiki = (function(XWiki) { */ abnormalUploadFinish : function (message) { clearInterval(this.timer); - this.formData.input.fire('xwiki:html5upload:message', {content: message, type: 'error', source: this, parameters : {name : this.file.name}}); + this.formData.input.fire('xwiki:html5upload:message', {content: message, type: 'error', source: this, parameters : + {name : this.file.name.escapeHTML()}}); this.formData.input.fire('xwiki:html5upload:fileFinished', {source: this}); } }); @@ -517,7 +518,7 @@ var XWiki = (function(XWiki) { } } catch (ex) { this.showMessage(ex, 'error', {size : UploadUtils.bytesToSize(this.options && this.options.maxFilesize), - name : file.name, type: file.type + name : file.name.escapeHTML(), type: file.type }); } }
Vulnerability mechanics
Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
10- github.com/advisories/GHSA-wf3x-jccf-5g5gghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2024-37900ghsaADVISORY
- github.com/xwiki/xwiki-platform/commit/6cdd69d31d6bf3caa7f40ec55eb317e4e528ad28ghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/commit/8b8a2d80529b9a9c038014c1eb6c2adc08069dfdghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/commit/910a5018a50039e8b24556573dfe342f143ef949ghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/commit/9df46f8e5313af46f93bccd1ebc682e28126573fghsax_refsource_MISCWEB
- github.com/xwiki/xwiki-platform/security/advisories/GHSA-wf3x-jccf-5g5gghsax_refsource_CONFIRMWEB
- jira.xwiki.org/browse/XWIKI-19602ghsax_refsource_MISCWEB
- jira.xwiki.org/browse/XWIKI-19611ghsax_refsource_MISCWEB
- jira.xwiki.org/browse/XWIKI-21769ghsax_refsource_MISCWEB
News mentions
0No linked articles in our index yet.