From 83cdc89be994416f74533030b90e8d1dd82fec57 Mon Sep 17 00:00:00 2001
From: Manuel <5673677+mtrezza@users.noreply.github.com>
Date: Tue, 20 Sep 2022 02:36:54 +0200
Subject: [PATCH] fix: session object properties can be updated by foreign
 user; this fixes a security vulnerability in which a foreign user can write
 to the session object of another user if the session object ID is known; the
 fix prevents writing to foreign session objects
 ([GHSA-6w4q-23cf-j9jp](https://github.com/parse-community/parse-server/security/advisories/GHSA-6w4q-23cf-j9jp))
 [skip release] (#8181)

---
 spec/ParseSession.spec.js | 28 ++++++++++++++++++++++++++++
 src/RestWrite.js          | 14 ++++++++++++++
 2 files changed, 42 insertions(+)

diff --git a/spec/ParseSession.spec.js b/spec/ParseSession.spec.js
index 084f141e08..176ed152f9 100644
--- a/spec/ParseSession.spec.js
+++ b/spec/ParseSession.spec.js
@@ -135,4 +135,32 @@ describe('Parse.Session', () => {
         fail(err);
       });
   });
+
+  it('cannot edit session with known ID', async () => {
+    const request = require('../lib/request');
+    await setupTestUsers();
+    const [first, second] = await new Parse.Query(Parse.Session).find({ useMasterKey: true });
+    const headers = {
+      'X-Parse-Application-Id': 'test',
+      'X-Parse-Rest-API-Key': 'rest',
+      'X-Parse-Session-Token': second.get('sessionToken'),
+      'Content-Type': 'application/json',
+    };
+    const firstUser = first.get('user').id;
+    const secondUser = second.get('user').id;
+    const e = await request({
+      method: 'PUT',
+      headers,
+      url: `http://localhost:8378/1/sessions/${first.id}`,
+      body: JSON.stringify({
+        foo: 'bar',
+        user: { __type: 'Pointer', className: '_User', objectId: secondUser },
+      }),
+    }).catch(e => e.data);
+    expect(e.code).toBe(Parse.Error.OBJECT_NOT_FOUND);
+    expect(e.error).toBe('Object not found.');
+    await Parse.Object.fetchAll([first, second], { useMasterKey: true });
+    expect(first.get('user').id).toBe(firstUser);
+    expect(second.get('user').id).toBe(secondUser);
+  });
 });
diff --git a/src/RestWrite.js b/src/RestWrite.js
index 2be833ad30..0fc07dc112 100644
--- a/src/RestWrite.js
+++ b/src/RestWrite.js
@@ -1018,6 +1018,20 @@ RestWrite.prototype.handleSession = function () {
     } else if (this.data.sessionToken) {
       throw new Parse.Error(Parse.Error.INVALID_KEY_NAME);
     }
+    if (!this.auth.isMaster) {
+      this.query = {
+        $and: [
+          this.query,
+          {
+            user: {
+              __type: 'Pointer',
+              className: '_User',
+              objectId: this.auth.user.id,
+            },
+          },
+        ],
+      };
+    }
   }
 
   if (!this.query && !this.auth.isMaster) {