CVE-2026-10514
Description
Stored XSS vulnerability in CordysCRM allows remote attackers to inject malicious scripts via announcement content.
AI Insight
LLM-synthesized narrative grounded in this CVE's description and references.
Stored XSS vulnerability in CordysCRM allows remote attackers to inject malicious scripts via announcement content.
Vulnerability
A stored cross-site scripting (XSS) vulnerability exists in CordysCRM versions up to 1.6.2, specifically within the AnnouncementController component's addAnnouncement() method. The vulnerability arises from a failure to adequately validate or encode the content parameter when processing new announcement requests. This affects the file backend/framework/src/main/java/cn/cordys/config/RequestParamTrimConfig.java [1].
Exploitation
A remote attacker can exploit this vulnerability by logging in with an account that has permissions to create announcements and submitting announcement content containing malicious JavaScript code, such as ``. This malicious announcement can then be viewed by any user on the system, including administrators or regular employees, leading to script execution in their browser environment [1].
Impact
Successful exploitation of this vulnerability allows an attacker to execute arbitrary JavaScript code in the victim's browser within the context of the CordysCRM application. This can lead to session hijacking, data theft, or further malicious actions against the user, depending on the privileges of the compromised user [1].
Mitigation
This vulnerability is mitigated by upgrading to version 1.7.0 or later. The patch identifier is c87682afa8df79853299f75489c9d333f7bc5fce [2]. Version 1.7.0 was released on 2026-05-29 [4].
AI Insight generated on Jun 2, 2026. Synthesized from this CVE's description and the cited reference URLs; citations are validated against the source bundle.
Affected products
1- Range: <=1.6.2
Patches
1c87682afa8dffix: Implement XSS protection with configurable URL filtering
3 files changed · +58 −23
backend/app/src/main/resources/commons.properties+2 −2 modified@@ -89,5 +89,5 @@ dashboard.whitelist.enabled=false # Enable whitelist functionality, if not enabled, access will not be restricted. dashboard.whitelist.allowed= -# Full HTML escaping switch. When enabled, all tags will be escaped (may affect content display), only enable for special scenarios. -xss.escape.all.enabled=false \ No newline at end of file +# List of URLs that require XSS filtering, supports Ant-style path matching, e.g., /api/**. If no URLs need to be filtered, it can be left empty. +# xss.protection.url.list=/account/follow/**,/announcement/add \ No newline at end of file
backend/framework/src/main/java/cn/cordys/config/RequestParamTrimConfig.java+54 −19 modified@@ -3,14 +3,19 @@ import com.fasterxml.jackson.core.JsonParser; import com.fasterxml.jackson.databind.DeserializationContext; import com.fasterxml.jackson.databind.deser.std.StdScalarDeserializer; +import jakarta.servlet.http.HttpServletRequest; import org.apache.commons.lang3.StringUtils; import org.springframework.beans.factory.annotation.Value; import org.springframework.boot.autoconfigure.jackson.Jackson2ObjectMapperBuilderCustomizer; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; +import org.springframework.util.AntPathMatcher; +import org.springframework.web.context.request.RequestContextHolder; +import org.springframework.web.context.request.ServletRequestAttributes; import org.springframework.web.util.HtmlUtils; import java.io.IOException; +import java.util.Arrays; /** * 配置类,用于定制 Jackson 的反序列化过程。 @@ -23,8 +28,13 @@ @Configuration public class RequestParamTrimConfig { - @Value("${xss.escape.all.enabled:false}") - private boolean escape; + /** + * 需要开启 XSS 过滤的 URL 列表(Ant 风格,逗号分隔)。 + * 示例:/account/follow/**,/announcement/** + * 留空表示不对任何请求做 HTML 转义。 + */ + @Value("${xss.protection.url.list:}") + private String xssFilterUrlList; /** * 定义一个 {@link Jackson2ObjectMapperBuilderCustomizer} Bean, @@ -37,24 +47,49 @@ public class RequestParamTrimConfig { */ @Bean public Jackson2ObjectMapperBuilderCustomizer jackson2ObjectMapperBuilderCustomizer() { - return jacksonObjectMapperBuilder -> { - // 为 String 类型字段定义自定义的反序列化操作 - jacksonObjectMapperBuilder - .deserializerByType(String.class, new StdScalarDeserializer<String>(String.class) { - @Override - public String deserialize(JsonParser jsonParser, DeserializationContext ctx) - throws IOException { - // 在反序列化时去除前后空格 - String value = StringUtils.trim(jsonParser.getValueAsString()); - - // 进一步清理可能的 XSS 攻击内容,开启后可能会导致一些特殊字符被转义,如 <、>、& 等 - if (escape) { - return HtmlUtils.htmlEscape(value); - } - return value; + AntPathMatcher pathMatcher = new AntPathMatcher(); // 线程安全,可复用 + + return builder -> builder + .deserializerByType(String.class, new StdScalarDeserializer<String>(String.class) { + @Override + public String deserialize(JsonParser p, DeserializationContext ctxt) throws IOException { + String rawValue = p.getValueAsString(); + String trimmedValue = StringUtils.trim(rawValue); + + // 判断是否需要对当前值进行 HTML 转义 + if (shouldEscapeXss(pathMatcher)) { + return HtmlUtils.htmlEscape(trimmedValue); } - }); - }; + return trimmedValue; + } + }); + } + + /** + * 判断当前请求是否命中 XSS 过滤白名单(命中 → 执行转义)。 + */ + private boolean shouldEscapeXss(AntPathMatcher pathMatcher) { + // 未配置过滤列表 + if (StringUtils.isBlank(xssFilterUrlList)) { + return false; + } + + ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes(); + if (attributes == null) { + return false; // 非 Web 上下文(定时任务等)不处理 + } + + HttpServletRequest request = attributes.getRequest(); + String requestURI = request.getRequestURI(); + if (StringUtils.isBlank(requestURI)) { + return false; + } + + // 逗号分隔的 Ant 路径列表,任一匹配即需要转义 + return Arrays.stream(xssFilterUrlList.split(",")) + .map(String::trim) + .filter(StringUtils::isNotBlank) // 过滤掉空白配置项 + .anyMatch(pattern -> pathMatcher.match(pattern, requestURI)); } }
installer/conf/cordys-crm.properties+2 −2 modified@@ -39,5 +39,5 @@ dashboard.whitelist.enabled=false # Enable whitelist functionality, if not enabled, access will not be restricted. dashboard.whitelist.allowed= -# Full HTML escaping switch. When enabled, all tags will be escaped (may affect content display), only enable for special scenarios. -xss.escape.all.enabled=false \ No newline at end of file +# List of URLs that require XSS filtering, supports Ant-style path matching, e.g., /api/**. If no URLs need to be filtered, it can be left empty. +xss.protection.url.list=/account/follow/**,/announcement/add \ No newline at end of file
Vulnerability mechanics
Root cause
"The application failed to properly sanitize user-supplied input before rendering it, leading to cross-site scripting."
Attack vector
A remote attacker can exploit this vulnerability by submitting malicious JavaScript code within announcement content via the `/announcement/add` interface [ref_id=1]. This malicious content is then stored and later rendered when other users view the announcement. The vulnerability is triggered when a user with permissions to create announcements crafts a payload, such as `<img src=x onerror='alert(1)'>`, and submits it [ref_id=1].
Affected code
The vulnerability resides in the `RequestParamTrimConfig.java` file, specifically within the `jackson2ObjectMapperBuilderCustomizer` method. Previously, an `escape` flag controlled whether `HtmlUtils.htmlEscape` was applied to all deserialized strings. The patch updates this logic to use a configurable `xssFilterUrlList` and an `AntPathMatcher` to conditionally apply HTML escaping based on the request URI [patch_id=4433601].
What the fix does
The patch modifies the `RequestParamTrimConfig.java` file to introduce configurable URL filtering for XSS protection [patch_id=4433601]. Instead of globally escaping all strings, the application now checks if the current request URI matches a configured list of URLs that require XSS filtering. If a match is found, the input string is HTML-escaped using `HtmlUtils.htmlEscape()`, preventing malicious scripts from executing [patch_id=4433601].
Preconditions
- authThe attacker must have an account with permissions to modify and create announcements.
- inputThe attacker must craft and submit a payload containing malicious JavaScript within the announcement content.
Reproduction
Log in with an account that has permission to modify and create announcements, and enter the announcement creation interface. The content created is as follows. The payload is as follows: <img src=x onerror='alert(1)'> The time must be set to a valid time; otherwise, the attack will fail and the announcement will not load. When selecting the recipient, you can choose to attack any user on the system. Here, you can select any user on the system or specify a user; select the "test" user. Click to preview. It can be observed that the payload is triggered. Clicking "OK" will create an announcement and trigger the following request data packet: POST /announcement/add HTTP/1.1 ... {"id":"","subject":"XSS_test","content":"<img src=x onerror='alert(1)'>", ...}. Open another browser, log in as the test user, and you can see that the payload is effective, indicating a stored XSS vulnerability. Reproduction complete. [ref_id=1]
Generated on Jun 2, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.
References
8- github.com/1Panel-dev/CordysCRM/commit/c87682afa8df79853299f75489c9d333f7bc5fcenvd
- github.com/1Panel-dev/CordysCRM/issues/2229nvd
- github.com/1Panel-dev/CordysCRM/pull/2356nvd
- github.com/1Panel-dev/CordysCRM/releases/tag/v1.7.0nvd
- vuldb.com/cve/CVE-2026-10514nvd
- vuldb.com/submit/828296nvd
- vuldb.com/vuln/367596nvd
- vuldb.com/vuln/367596/ctinvd
News mentions
0No linked articles in our index yet.