Vulnerability: Wiki.js is a wiki app built on Node.js. In affected versions an authenticated user with write access on a restricted set of paths can update a page outside the allowed paths by specifying a different target page ID while keeping the path intact. The access control incorrectly check the path access against the user-provided values instead of the actual path associated to the page ID. Commit https://github.com/Requarks/wiki/commit/411802ec2f654bb5ed1126c307575b81e2361c6b fixes this vulnerability by checking access control on the path associated with the page ID instead of the user-provided value. When the path is different than the current value, a second access control check is then performed on the user-provided path before the move operation.
Vulnerability ID: CVE-2022-23654
CWE: CWE-287
Severity score: 2.9
Project: https://github.com/Requarks/wiki
Published: 2022-02-22
File: server/models/pages.js
Commit message: fix: check update page access using original page path
Commit author: NGPixel

Vulnerable version (before fix):
 module.exports = class Page extends Model {      // -> Check for page access     if (!WIKI.auth.checkAccess(opts.user, ['write:pages'], {       locale: opts.locale,       path: opts.path     })) {       throw new WIKI.Error.PageUpdateForbidden()     } module.exports = class Page extends Model {      // -> Perform move?     if ((opts.locale && opts.locale !== page.localeCode) || (opts.path && opts.path !== page.path)) {       await WIKI.models.pages.movePage({         id: page.id,         destinationLocale: opts.locale,

Fixed version (after fix):
 module.exports = class Page extends Model {      // -> Check for page access     if (!WIKI.auth.checkAccess(opts.user, ['write:pages'], {       locale: ogPage.localeCode,       path: ogPage.path     })) {       throw new WIKI.Error.PageUpdateForbidden()     } module.exports = class Page extends Model {      // -> Perform move?     if ((opts.locale && opts.locale !== page.localeCode) || (opts.path && opts.path !== page.path)) {       // -> Check target path access       if (!WIKI.auth.checkAccess(opts.user, ['write:pages'], {         locale: opts.locale,         path: opts.path       })) {         throw new WIKI.Error.PageMoveForbidden()       }        await WIKI.models.pages.movePage({         id: page.id,         destinationLocale: opts.locale,

Patch:
patch: @@ -371,8 +371,8 @@ module.exports = class Page extends Model {
 
     // -> Check for page access
     if (!WIKI.auth.checkAccess(opts.user, ['write:pages'], {
-      locale: opts.locale,
-      path: opts.path
+      locale: ogPage.localeCode,
+      path: ogPage.path
     })) {
       throw new WIKI.Error.PageUpdateForbidden()
     }
@@ -456,6 +456,14 @@ module.exports = class Page extends Model {
 
     // -> Perform move?
     if ((opts.locale && opts.locale !== page.localeCode) || (opts.path && opts.path !== page.path)) {
+      // -> Check target path access
+      if (!WIKI.auth.checkAccess(opts.user, ['write:pages'], {
+        locale: opts.locale,
+        path: opts.path
+      })) {
+        throw new WIKI.Error.PageMoveForbidden()
+      }
+
       await WIKI.models.pages.movePage({
         id: page.id,
         destinationLocale: opts.locale,
path: server/models/pages.js