Try to upload a file larger than the size limit by uploading it thanks to the attachment tab of any page were the user has edit rights. It will fail, as expected.
Switch to edit mode in this page
Drag and drop the same file in the page
Expected result: the upload is blocked
Actual result: the upload is successful and the link in the page created
2 updates
Changes by LAMBLIN on 10/Jun/26 14:37
Assignee:
Vincent Massol
Changes by Vincent Massol on 10/Jun/26 14:37
Summary:
Uploading a file by drag- and dropping it-drop in edit mode will bypass the WYSIWYG editor doesn't honor the size limitation for attachments
1 comment
Vincent Massol on 10/Jun/26 14:38
Analysis:
Context
The XWiki "Size Limit" feature (the upload_maxsize space/wiki preference, default 32 MB) is
documented at AdminGuide/Attachments. The user observes that the limit is enforced when
uploading via the classic attachment tab at the bottom of a page, but not when an image is
drag-and-dropped into the WYSIWYG editor (which attaches the image to the page). This documents
where the size check lives, why the two paths diverge, and a proposed fix.
Where the size limit is actually checked
There are two enforcement mechanisms, both reading the same upload_maxsize preference:
1. Application-level validator — FileSizeAttachmentValidationStep
xwiki-platform-attachment/.../validation/internal/step/FileSizeAttachmentValidationStep.java:61
Compares wrapper.getSize() against getSpacePreferenceAsLong("upload_maxsize", 32MB) and throws
AttachmentValidationException (HTTP 413) if exceeded. Invoked first by
DefaultAttachmentValidator.validateAttachment() (.../internal/DefaultAttachmentValidator.java:74).
2. Parser-level cap — ServletFileUpload.setSizeMax(uploadMaxSize) in
oldcore/.../internal/fileupload/FileUploadUtils.java:137. Only used in the legacy
commons-fileupload fallback branch (when the servlet container did NOT already parse the
multipart request). On modern servlet containers (Jetty/Tomcat multipart enabled) this branch is
never taken — see below.
The root cause of the asymmetry
FileUploadUtils.getFileItems() (oldcore/.../internal/fileupload/FileUploadUtils.java:83) is the
shared entry point used by the fileupload plugin. On a modern servlet container request.getParts()
is non-empty, so it takes the servlet-Part branch (lines 100-109):
for (Part part : parts) {
if (Strings.CS.startsWith(part.getName(), UploadAction.FILE_FIELD_NAME)) { // "filepath"
attachmentValidator.validateAttachment(new PartAttachmentAccessWrapper(part));
}
items.add(new PartFileItem(part));
}
Validation only runs for parts whose field name starts with filepath (UploadAction.FILE_FIELD_NAME).
The parser-level setSizeMax in the else branch is skipped entirely here.
- Attachment tab → posts to the upload action with file field filepath0 → matches the
filter → validated → limit enforced. (UploadAction.java:67,124)
- WYSIWYG editor → posts to the XWiki.WYSIWYG.FileUploader sheet with file field upload
(FileUploader.xml:64,113,122). The sheet chooses one of two macros based on the
X-XWiki-Temporary-Attachment-Support request header (FileUploader.xml:202):
- handleTemporaryUploadRequest (header = true): calls
temporaryAttachments.uploadTemporaryAttachment(...) →
DefaultTemporaryAttachmentSessionsManager.uploadAttachment() which explicitly calls
validateAttachment(...) (store-filesystem-oldcore/.../DefaultTemporaryAttachmentSessionsManager.java:144).
→ limit enforced.
- handleUploadRequest (header absent/false): uses
$xwiki.fileupload.getFileItemData('upload') → FileUploadPlugin.loadFileList →
FileUploadUtils.getFileItems. Because the field name is upload (not filepath), the
servlet-Part branch skips validation, and setSizeMax is not applied. → limit NOT enforced.
When does the WYSIWYG fall into the non-validating handleUploadRequest path?
The CKEditor xwiki-upload plugin sends the header from
editor.config['xwiki-upload'].isTemporaryAttachmentSupported
(xwiki-upload/plugin.js:223). That flag is true by default (CKEditor/ConfigSheet.xml:56,175,
set when the temporaryAttachments script service is present), but is forced to false when:
- Realtime / collaborative editing is active — ckeditorRealtimeAdapter.js:489 explicitly sets
isTemporaryAttachmentSupported = false.
- Editing an existing or new translation — FileUploader.xml:202 (!$document.isTranslation() && !$isNewTranslation).
- The temporaryAttachments script service is unavailable (older/edge installs).
In those situations a drag-and-dropped image is uploaded under field name upload via the legacy
macro and bypasses the size limit entirely.
Proposed fix
Make the multipart-level validation field-name-agnostic so any uploaded file part is validated,
not just filepath*. In FileUploadUtils.getFileItems() servlet-Part branch
(oldcore/.../internal/fileupload/FileUploadUtils.java:102-107), change the gate from
"name starts with filepath" to "the part is an actual file upload" (i.e.
part.getSubmittedFileName() != null), which still skips plain form fields (xredirect, form_token,
filename*, etc.) since those have no submitted filename.
for (Part part : parts) {
if (part.getSubmittedFileName() != null) { // any uploaded file, regardless of field name
attachmentValidator.validateAttachment(new PartAttachmentAccessWrapper(part));
}
items.add(new PartFileItem(part));
}
This fixes the legacy WYSIWYG handleUploadRequest path and any other consumer of the fileupload
plugin that uses a non-filepath field name, while the temporary-attachment path keeps its existing
explicit validation. PartAttachmentAccessWrapper.getSize() returns part.getSize()
(oldcore/.../PartAttachmentAccessWrapper.java:54), so the size is available without consuming the
stream.
Files involved:
- xwiki-platform-core/xwiki-platform-oldcore/src/main/java/com/xpn/xwiki/internal/fileupload/FileUploadUtils.java (the fix)
Note: this changes behavior to reject oversized non-filepath uploads that previously slipped
through; confirm with the user this is the intended scope before implementing.
Verification
1. Build oldcore: mvn clean install -pl xwiki-platform-core/xwiki-platform-oldcore -Plegacy,snapshot -DskipITs.
2. Set a small upload_maxsize (e.g. 1024) in XWiki.XWikiPreferences / space WebPreferences.
3. Attachment tab: upload a file > limit → must be rejected (regression check — already works).
4. WYSIWYG drag-drop, realtime editing ON (forces isTemporaryAttachmentSupported=false): drop an
image > limit → must now be rejected.
5. WYSIWYG drag-drop, normal editing (temp attachments): drop an image > limit → still rejected.
6. Add/extend a unit test for FileUploadUtils.getFileItems() asserting that a file part named
upload exceeding the limit triggers validateAttachment / AttachmentValidationException.
This message was sent by Atlassian Jira (v9.3.0#930000-sha1:287aeb6)
If image attachments aren't displayed, see this article.