CVE-2022-3978: Cross-Site Request Forgery (CSRF) (CWE-352)
value: A vulnerability, which was classified as problematic, was found in NodeBB up to 2.5.7. This affects an unknown part of the file /register/abort. The manipulation leads to cross-site request forgery. It is possible to initiate the attack remotely. Upgrading to version 2.5.8 is able to address this issue. The name of the patch is 2f9d8c350e54543f608d3d4c8e1a49bbb6cdea38. It is recommended to upgrade the affected component. The associated identifier of this vulnerability is VDB-213555.
CWE description: The web application does not, or can not, sufficiently verify whether a well-formed, valid, consistent request was intentionally provided by the user who submitted the request.
CVSS v3 base score: 4.3
Published: 2022-11-13T14:15Z
Repository: https://github.com/NodeBB/NodeBB
Language: JavaScript
Files changed: test/api.js, test/controllers.js, test/user.js
Commit date: 2022-11-09 13:20:28 -0500
Commit message: fix: pass csrf_token into calls to /register/abort, #11017

Diff: diff --git a/test/api.js b/test/api.js
index ab8094cc76..cc13650770 100644
--- a/test/api.js
+++ b/test/api.js
@@ -483,11 +483,11 @@ describe('API', async () => {
 
 				it('should back out of a registration interstitial if needed', async () => {
 					const affectedPaths = ['GET /api/user/{userslug}/edit/email'];
 					if (affectedPaths.includes(`${method.toUpperCase()} ${path}`)) {
 						await request({
-							uri: `${nconf.get('url')}/register/abort`,
+							uri: `${nconf.get('url')}/register/abort?_csrf=${csrfToken}`,
 							method: 'POST',
 							jar,
 							simple: false,
 						});
 					}
diff --git a/test/controllers.js b/test/controllers.js
index bb7cdedc7b..f255380446 100644
--- a/test/controllers.js
+++ b/test/controllers.js
@@ -1235,12 +1235,14 @@ describe('Controllers', () => {
 		});
 	});
 
 	describe('account pages', () => {
 		let jar;
+		let csrf_token;
+
 		before(async () => {
-			({ jar } = await helpers.loginUser('foo', 'barbar'));
+			({ jar, csrf_token } = await helpers.loginUser('foo', 'barbar'));
 		});
 
 		it('should redirect to account page with logged in user', (done) => {
 			request(`${nconf.get('url')}/api/login`, { jar: jar, json: true }, (err, res, body) => {
 				assert.ifError(err);
@@ -1800,11 +1802,11 @@ describe('Controllers', () => {
 
 			assert.strictEqual(res.statusCode, 200);
 			assert.strictEqual(res.body, '/register/complete');
 
 			await requestAsync({
-				uri: `${nconf.get('url')}/register/abort`,
+				uri: `${nconf.get('url')}/register/abort?_csrf=${csrf_token}`,
 				method: 'post',
 				jar,
 				simple: false,
 			});
 		});
diff --git a/test/user.js b/test/user.js
index 1a8971f258..176ee82827 100644
--- a/test/user.js
+++ b/test/user.js
@@ -812,19 +812,20 @@ describe('User', () => {
 	});
 
 	describe('profile methods', () => {
 		let uid;
 		let jar;
+		let csrf_token;
 
 		before(async () => {
 			const newUid = await User.create({ username: 'updateprofile', email: 'update@me.com', password: '123456' });
 			uid = newUid;
 
 			await User.setUserField(uid, 'email', 'update@me.com');
 			await User.email.confirmByUid(uid);
 
-			({ jar } = await helpers.loginUser('updateprofile', '123456'));
+			({ jar, csrf_token } = await helpers.loginUser('updateprofile', '123456'));
 		});
 
 		it('should return error if not logged in', async () => {
 			try {
 				await apiUser.update({ uid: 0 }, { uid: 1 });
@@ -1285,11 +1286,11 @@ describe('User', () => {
 			assert.strictEqual(res.statusCode, 200);
 			assert(res.body);
 
 			// Accessing this page will mark the user's account as needing an updated email, below code undo's.
 			await requestAsync({
-				uri: `${nconf.get('url')}/register/abort`,
+				uri: `${nconf.get('url')}/register/abort?_csrf=${csrf_token}`,
 				jar,
 				method: 'POST',
 				simple: false,
 			});
 		});

Vulnerable code: 							uri: `${nconf.get('url')}/register/abort`,
			({ jar } = await helpers.loginUser('foo', 'barbar'));
				uri: `${nconf.get('url')}/register/abort`,
			({ jar } = await helpers.loginUser('updateprofile', '123456'));
				uri: `${nconf.get('url')}/register/abort`,
Fixed code: 							uri: `${nconf.get('url')}/register/abort?_csrf=${csrfToken}`,
		let csrf_token;

			({ jar, csrf_token } = await helpers.loginUser('foo', 'barbar'));
				uri: `${nconf.get('url')}/register/abort?_csrf=${csrf_token}`,
		let csrf_token;
			({ jar, csrf_token } = await helpers.loginUser('updateprofile', '123456'));
				uri: `${nconf.get('url')}/register/abort?_csrf=${csrf_token}`,