Details
Description
Problem
XWIKI-23902 added a protection against path traversal when WebJar resources are copied to the filesystem during an HTML export. The check in FilesystemResourceReferenceCopier#copyResourceFromJAR compares the two canonical paths as plain strings:
String canonicalTargetPath = targetLocation.getCanonicalPath(); String canonicalExportPath = exportDirectory.getCanonicalPath(); if (canonicalTargetPath.startsWith(canonicalExportPath)) {
String.startsWith does not stop at a path component boundary. A target such as /tmp/xwiki/export-evil/poc.txt therefore passes the check for the export directory /tmp/xwiki/export, even though it is a sibling of the export directory and not inside it.
A WebJar containing a JAR entry whose name escapes the export directory (for example META-INF/resources/webjars/../../export-evil/poc.txt) can consequently have its content written next to the export directory instead of inside it. Installing a WebJar only requires the ADMIN right, not Programming Right, so this is a weaker check than the one the protection is meant to enforce.
Why this is not currently exploitable
The escape only works if the attacker can name a sibling directory whose name starts with the export directory's own name, which means knowing that name when the WebJar is built. In practice the export directory is created by HtmlPackager as a fresh RandomStringUtils.secure().nextAlphanumeric(8) directory under the temporary directory, and it is regenerated for every export, so the name is not predictable. Even with a correct guess, the write stays confined to a path that starts with the export directory's absolute path, i.e. a sibling inside XWiki's own temporary directory.
This is therefore reported as a hardening issue and not as a vulnerability: the correctness of the check currently rests on an unrelated decision in HtmlPackager to randomise the directory name, rather than on the check itself.
Fix
Compare path components instead of characters, using java.nio.file.Path#startsWith.