CVE-2025-32960
Description
The CUBA REST API add-on performs operations on data and entities. Prior to version 7.2.7, the input parameter, which consists of a file path and name, can be manipulated to return the Content-Type header with text/html if the name part ends with .html. This could allow malicious JavaScript code to be executed in the browser. For a successful attack, a malicious file needs to be uploaded beforehand. This issue has been patched in version 7.2.7. A workaround is provided on the Jmix documentation website.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
CVE-2025-32960 is an XSS vulnerability in the CUBA REST API add-on where a crafted file name ending in .html causes the /files endpoint to return text/html, enabling script execution.
Root
Cause
The CUBA REST API add-on's /files endpoint determines the Content-Type header based on the file extension in the request parameter. If the file name ends with .html, the endpoint returns text/html instead of a safe MIME type, allowing the browser to interpret the response as HTML [1].
Exploitation
An attacker must first upload a malicious file (e.g., containing JavaScript) to the file storage. Then, by requesting that file via the /files endpoint with a name ending in .html, the server serves the file with Content-Type: text/html, causing the browser to execute any embedded script [1]. The attack requires prior upload capability but no additional authentication beyond normal access to the endpoint.
Impact
Successful exploitation leads to stored cross-site scripting (XSS) in the context of the application. An attacker can execute arbitrary JavaScript in the browser of any user who views the malicious file, potentially stealing session cookies, performing actions on behalf of the victim, or defacing the application.
Mitigation
The vulnerability is patched in CUBA REST API add-on version 7.2.7 [1]. The fix introduces a configuration property (cuba.rest.inlineEnabledFileExtensions) that restricts which file extensions can be served inline, defaulting to safe types like jpg, png, jpeg, and pdf [4]. For users unable to upgrade immediately, the recommended workaround is to disable the /files REST endpoint entirely [1].
AI Insight generated on May 20, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected packages
Versions sourced from the GitHub Security Advisory.
| Package | Affected versions | Patched versions |
|---|---|---|
com.haulmont.addon.restapi:restapi-rest-apiMaven | < 7.2.7 | 7.2.7 |
Affected products
1- Range: v7.2.0, v7.2.0.BETA1, v7.2.0.BETA2, …
Patches
260fc55de808eb3d599f6657dBackport REST files fix #147
2 files changed · +34 −0
modules/global/src/com/haulmont/addon/restapi/api/config/RestApiConfig.java+9 −0 modified@@ -21,6 +21,7 @@ import com.haulmont.cuba.core.config.Property; import com.haulmont.cuba.core.config.Source; import com.haulmont.cuba.core.config.SourceType; +import com.haulmont.cuba.core.config.defaults.Default; import com.haulmont.cuba.core.config.defaults.DefaultBoolean; import com.haulmont.cuba.core.config.defaults.DefaultString; import com.haulmont.cuba.core.config.type.CommaSeparatedStringListTypeFactory; @@ -123,4 +124,12 @@ public interface RestApiConfig extends Config { @Factory(factory = UuidTypeFactory.class) @Nullable UUID getRestAnonymousSessionId(); + + /** + * File extensions that can be opened for viewing in a browser by replying with 'Content-Disposition=inline' header. + */ + @Property("cuba.rest.inlineEnabledFileExtensions") + @Factory(factory = CommaSeparatedStringListTypeFactory.class) + @Default("jpg, png, jpeg, pdf") + List<String> getInlineEnabledFileExtensions(); } \ No newline at end of file
modules/rest-api/src/com/haulmont/addon/restapi/api/controllers/FileDownloadController.java+25 −0 modified@@ -16,13 +16,15 @@ package com.haulmont.addon.restapi.api.controllers; +import com.haulmont.addon.restapi.api.config.RestApiConfig; import com.haulmont.addon.restapi.api.exception.RestAPIException; import com.haulmont.bali.util.URLEncodeUtils; import com.haulmont.cuba.core.app.DataService; import com.haulmont.cuba.core.entity.FileDescriptor; import com.haulmont.cuba.core.global.*; import com.haulmont.cuba.core.sys.remoting.discovery.ServerSelector; import com.haulmont.cuba.security.entity.EntityOp; +import org.apache.commons.io.FilenameUtils; import org.apache.commons.io.IOUtils; import org.apache.commons.lang3.BooleanUtils; import org.apache.commons.lang3.StringUtils; @@ -37,6 +39,7 @@ import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.io.InputStream; +import java.util.List; import java.util.UUID; /** @@ -65,6 +68,9 @@ public class FileDownloadController { @Inject protected Security security; + @Inject + protected RestApiConfig restApiConfig; + @GetMapping("/{fileDescriptorId}") public void downloadFile(@PathVariable String fileDescriptorId, @RequestParam(required = false) Boolean attachment, @@ -87,6 +93,8 @@ public void downloadFile(@PathVariable String fileDescriptorId, throw new RestAPIException("File not found", "File not found. Id: " + fileDescriptorId, HttpStatus.NOT_FOUND); } + attachment = resolveAttachmentValue(attachment, fd); + try { response.setHeader("Cache-Control", "no-cache"); response.setHeader("Pragma", "no-cache"); @@ -130,4 +138,21 @@ protected void checkCanReadFileDescriptor() { HttpStatus.FORBIDDEN); } } + + protected boolean resolveAttachmentValue(Boolean attachmentRequestParameterValue, FileDescriptor fileDescriptor) { + if (BooleanUtils.isTrue(attachmentRequestParameterValue)) { + return true; + } + + String fileName = fileDescriptor.getName(); + String extension = FilenameUtils.getExtension(fileName); + if (StringUtils.isEmpty(extension)) { + // No extension - just download + return true; + } else { + // Check if file is allowed to be opened inline + List<String> inlineEnabledFileExtensions = restApiConfig.getInlineEnabledFileExtensions(); + return !inlineEnabledFileExtensions.contains(StringUtils.lowerCase(extension)); + } + } } \ No newline at end of file
Vulnerability mechanics
Generated on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
7- github.com/advisories/GHSA-88h5-34xw-2q56ghsaADVISORY
- nvd.nist.gov/vuln/detail/CVE-2025-32960ghsaADVISORY
- docs.jmix.io/jmix/files-vulnerabilities.htmlnvdWEB
- docs.jmix.io/jmix/files-vulnerabilities.htmlnvdWEB
- github.com/cuba-platform/restapi/commit/b3d599f6657d7e212fdb134a61ab5e0888669eb1nvdWEB
- github.com/cuba-platform/restapi/security/advisories/GHSA-88h5-34xw-2q56nvdWEB
- github.com/jmix-framework/jmix/security/advisories/GHSA-x27v-f838-jh93nvdWEB
News mentions
0No linked articles in our index yet.