CVE-2026-120326 (Vaadin Flow): planned Jmix 2.8.x patch with Vaadin 24.10.14+?

Hello Jmix team,

We’re using Jmix 2.8.x and noticed this advisory: CVE-2026-120326: Unescaped download file name allows Content-Disposition parameter injection in Vaadin Flow

From the link above, here is the vulnerability breakdown:

The Issue: The download file name is written into the Content-Disposition header without escaping. A double quote in the name lets an attacker inject a filename* parameter, so the browser saves the file under a name and extension the attacker chooses.

Severity: Medium (CVSS score of 4.8).

Affected Versions: Vaadin 24.8 to 25.3. Jmix 2.8.6 uses Vaadin 24.10.7, which is within the affected range. Vaadin’s fix (24.10.14) is available only under its Enterprise subscription.

Exposure Condition: Your application must pass a file name it did not generate itself (e.g. the name a user uploaded the file with) to DownloadEvent.setFileName() or DownloadEvent.inline(). If your application only uses file names it generates itself, it is not vulnerable.

From the breakdown, our application is impacted. Therefore, we’d like to know how to handle it before we go live.

  1. Will Jmix release a patch for 2.8.x?
  2. If not, what is the recommended solution or workaround?

Best Regards.
Syauqi Hafizuddin

Hello @syauqi

First, let me clarify what is affected by this vulnerability.

The application code that uses io.jmix.flowui.download.Downloader is not affected. It does not rely on the header produced by Vaadin: it writes its own Content-Disposition header using Spring’s ContentDisposition , which encodes the name according to RFC 2047 and RFC 5987.

Your application is vulnerable only if you use Vaadin’s DownloadHandler directly, for example like this:

import com.vaadin.flow.component.html.Anchor;
import com.vaadin.flow.router.Route;
import com.vaadin.flow.server.streams.DownloadHandler;
import com.vaadin.flow.server.streams.DownloadResponse;
import io.jmix.core.FileRef;
import io.jmix.core.FileStorage;

import java.io.ByteArrayInputStream;
import java.nio.charset.StandardCharsets;

// ...
public class FromInputStreamExampleView extends StandardView {

    @ViewComponent
    private Anchor downloadLink;
    @Autowired
    private FileStorage fileStorage;

    @Subscribe
    public void onInit(final InitEvent event) {
        // Stands for a file uploaded by a user: its name is fully under the user's control.
        FileRef fileRef = fileStorage.saveStream(
                "invoice\"; filename*=UTF-8''invoice.exe; x=\".pdf",
                new ByteArrayInputStream("demo file content\n".getBytes(StandardCharsets.UTF_8)));

        // Vaadin passes the given name to DownloadEvent.setFileName() as is.
        downloadLink.setHref(DownloadHandler.fromInputStream(downloadEvent ->
                new DownloadResponse(
                        fileStorage.openStream(fileRef),
                        fileRef.getFileName(),
                        fileRef.getContentType(),
                        -1)));
    }
}

Second, about the fixes from Vaadin.
Obviously, we cannot include commercial versions of Vaadin in our free patches of Jmix 2.8. But you can purchase Vaadin’s Extended Maintenance and use their patched versions in your application, just by specifying the version explicitly in your build.gradle:

dependencies {  
   implementation platform('com.vaadin:vaadin-bom:24.x.x')  
   // ...  
}

If you would like to discuss the purchase of Vaadin Extended Maintenance, please contact us at info@jmix.io.

Regards,
Konstantin

1 Like