{"id":"GHSA-r5xw-gcgw-hwp5","summary":"YesWiki Vulnerable to Reflected XSS via Unescaped `id` Parameter in Bazar Widget HTML Attributes","details":"### Summary\nYesWiki's Bazar widget handler reflects the `id` `GET` parameter into HTML attributes using `strip_tags()` only. Because `strip_tags()` does not escape double quotes, an attacker can break out of the attribute value, inject an event handler such as `onmouseover`, and execute arbitrary JavaScript in the victim's browser.\n\nThis issue is reachable without authentication. During validation, the vulnerable `widget` route returned the injected HTML for both `/HomePage/widget?id=...` and `/NoSuchPage/widget?id=...`, which shows that no login, no page ownership, no edit rights, and not even a valid page tag were required. The only routing prerequisite observed was that the Bazar extension is enabled and the request includes an `id` parameter.\n\n### Details\nThe primary sink is in `tools/bazar/presentation/templates/widget.tpl.html` around lines `4-7`, where `$_GET['id']` is inserted into the `data-formid` attribute:\n\n```php\ndata-formid=\"\u003c?php echo strip_tags($_GET['id']); ?\u003e\"\n```\n\n`strip_tags()` is not an output-encoding function. It removes HTML tags, but it does not escape characters such as double quotes, so an attacker can terminate the `data-formid` attribute and inject new attacker-controlled attributes.\n\nThe route is served by `tools/bazar/handlers/__WidgetHandler.php` around lines `14-26`, which only checks whether `$_GET['id']` is present:\n\n```php\nif (!isset($_GET['id'])) {\n    return null;\n}\n```\n\nNo `HasAccess('read')`, `HasAccess('write')`, or authentication check is performed before the vulnerable template is rendered.\n\nThere is also a second reflection path in the same handler. The handler builds:\n\n```php\n$urlParams = 'id=' . strip_tags($_GET['id']) . ...\n```\n\nand then places the resulting value into the widget template's `data-iframeUrl` attribute:\n\n```php\ndata-iframeUrl=\"\u003c?php echo $GLOBALS['wiki']-\u003ehref('bazariframe', '', $urlparams, false); ?\u003e\"\n```\n\nDuring validation, a single payload injected into `id` was reflected into both `data-formid` and `data-iframeUrl`, which confirms that the handler exposes multiple attribute-level sinks from the same unsafely handled input.\n\nThis issue maps to **CWE-79: Improper Neutralization of Input During Web Page Generation ('Cross-site Scripting')**.\n\n### PoC\n1. Set up a vulnerable YesWiki instance with the bundled Bazar extension enabled. This was validated locally on the official `doryphore 4.6.5` release.\n2. Confirm the minimum access requirements:\n   - No account is required.\n   - No `read` or `write` permission on a specific page is required.\n   - No valid existing page tag is required.\n   - No valid Bazar form identifier is required.\n   - The only observed requirements were that the Bazar widget handler is present and the request includes an `id` parameter.\n3. Request the widget handler with an attribute-breaking payload in `id`, for example:\n\n```text\nhttp://127.0.0.1:8085/NoSuchPage/widget?id=%22%20onmouseover=%22alert(1)%22%20x=%22\n```\n\n4. Open the URL in a browser as an unauthenticated visitor.\n5. Observe that the server returns HTTP `200` and renders the Bazar widget page even though the page tag is arbitrary.\n6. Inspect the returned HTML. The response contains attacker-controlled attributes in the widget root element:\n\n```html\n\u003cdiv id=\"widgetapp\" v-cloak\n  data-formid=\"\" onmouseover=\"alert(1)\" x=\"\"\n  ...\n  data-iframeUrl=\"http://127.0.0.1:8085/NoSuchPage/bazariframe&id=\" onmouseover=\"alert(1)\" x=\"\"\n\u003e\n```\n\n7. Move the mouse over the `widgetapp` element or otherwise trigger the injected event handler.\n8. The browser executes the injected JavaScript in the YesWiki origin.\n\n\u003cimg width=\"1600\" height=\"838\" alt=\"image\" src=\"https://github.com/user-attachments/assets/de592586-a6ee-48f4-bbde-137ab07aaa71\" /\u003e\n\n### Impact\nThis is a **reflected XSS** vulnerability in the Bazar widget handler with very low attacker prerequisites.\n\nThe practical access model is:\n\n- The attacker only needs to send a crafted public URL.\n- The victim does not need to authenticate.\n- The attacker does not need edit rights, ownership, or a valid page tag.\n- The route only needs to be reachable on a YesWiki instance with Bazar enabled.\n\nAn attacker may be able to:\n\n- Execute arbitrary JavaScript in the victim's browser.\n- Steal browser-accessible sensitive data.\n- Perform actions in the victim's session if the victim is logged in.\n- Target public visitors and authenticated users alike because the route is reachable without access-control checks.","aliases":["CVE-2026-52774"],"modified":"2026-07-09T21:26:41.857629Z","published":"2026-07-09T21:01:10Z","database_specific":{"severity":"MODERATE","github_reviewed":true,"github_reviewed_at":"2026-07-09T21:01:10Z","nvd_published_at":null,"cwe_ids":["CWE-80"]},"references":[{"type":"WEB","url":"https://github.com/YesWiki/yeswiki/security/advisories/GHSA-r5xw-gcgw-hwp5"},{"type":"WEB","url":"https://github.com/YesWiki/yeswiki/commit/1aa2710c7505630b858f2142a65f9441bfaba2b2"},{"type":"PACKAGE","url":"https://github.com/YesWiki/yeswiki"}],"affected":[{"package":{"name":"yeswiki/yeswiki","ecosystem":"Packagist","purl":"pkg:composer/yeswiki/yeswiki"},"ranges":[{"type":"ECOSYSTEM","events":[{"introduced":"0"},{"fixed":"4.6.6"}]}],"versions":["4.2.3","v4.1.0","v4.1.1","v4.1.2","v4.1.3","v4.1.4","v4.1.5","v4.2.0","v4.2.1","v4.2.2","v4.2.4","v4.3","v4.3.1","v4.4.0","v4.4.1","v4.4.2","v4.4.3","v4.4.4","v4.4.5","v4.5.0","v4.5.1","v4.5.2","v4.5.3","v4.5.4","v4.5.5","v4.6.0","v4.6.1","v4.6.2","v4.6.3","v4.6.4","v4.6.5"],"database_specific":{"source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/07/GHSA-r5xw-gcgw-hwp5/GHSA-r5xw-gcgw-hwp5.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:C/C:L/I:L/A:N"}]}