CVE-2024-29027 (published 2024-03-19T19:15Z)

Parse Server is an open source backend that can be deployed to any infrastructure that can run Node.js. Prior to versions 6.5.5 and 7.0.0-alpha.29, calling an invalid Parse Server Cloud Function name or Cloud Job name crashes the server and may allow for code injection, internal store manipulation or remote code execution. The patch in versions 6.5.5 and 7.0.0-alpha.29 added string sanitation for Cloud Function name and Cloud Job name. As a workaround, sanitize the Cloud Function name and Cloud Job name before it reaches Parse Server.


Weakness information:
cwe_id: NVD-CWE-noinfo
cwe_name: Insufficient Information
description: There is insufficient information about the issue to classify it; details are unkown or unspecified.
extended_description: Insufficient Information

Fix information:
repo_url: https://github.com/parse-community/parse-server
commit_details: repo_url: https://github.com/parse-community/parse-server
author: Manuel
author_date: 2024-03-19 17:42:00+01:00
msg: fix: Server crashes on invalid Cloud Function or Cloud Job name; fixes security vulnerability [GHSA-6hh7-46r2-vf29](https://github.com/parse-community/parse-server/security/advisories/GHSA-6hh7-46r2-vf29) (#9024)
repository: repo_url: https://github.com/parse-community/parse-server
repo_name: parse-community/parse-server
description: Parse Server for Node.js / Express
repo_language: JavaScript
owner: parse-community
file_changes: filename: ParseHooks.spec.js
change_type: ModificationType.MODIFY
diff: @@ -694,3 +694,36 @@ describe('triggers', () => {
     expect(req.context).toBeUndefined();
   });
 });
+
+describe('sanitizing names', () => {
+  const invalidNames = [
+    `test'%3bdeclare%20@q%20varchar(99)%3bset%20@q%3d'%5c%5cxxxxxxxxxxxxxxx.yyyyy'%2b'fy.com%5cxus'%3b%20exec%20master.dbo.xp_dirtree%20@q%3b--%20`,
+    `test.function.name`,
+  ];
+
+  it('should not crash server and return error on invalid Cloud Function name', async () => {
+    for (const invalidName of invalidNames) {
+      let error;
+      try {
+        await Parse.Cloud.run(invalidName);
+      } catch (err) {
+        error = err;
+      }
+      expect(error).toBeDefined();
+      expect(error.message).toMatch(/Invalid function/);
+    }
+  });
+
+  it('should not crash server and return error on invalid Cloud Job name', async () => {
+    for (const invalidName of invalidNames) {
+      let error;
+      try {
+        await Parse.Cloud.startJob(invalidName);
+      } catch (err) {
+        error = err;
+      }
+      expect(error).toBeDefined();
+      expect(error.message).toMatch(/Invalid job/);
+    }
+  });
+});

programming_language: TypeScript
filename: triggers.js
change_type: ModificationType.MODIFY
diff: @@ -86,6 +86,12 @@ const Category = {
 };
 
 function getStore(category, name, applicationId) {
+  const invalidNameRegex = /['"`]/;
+  if (invalidNameRegex.test(name)) {
+    // Prevent a malicious user from injecting properties into the store
+    return {};
+  }
+
   const path = name.split('.');
   path.splice(-1); // remove last component
   applicationId = applicationId || Parse.applicationId;
@@ -94,7 +100,7 @@ function getStore(category, name, applicationId) {
   for (const component of path) {
     store = store[component];
     if (!store) {
-      return undefined;
+      return {};
     }
   }
   return store;

programming_language: TypeScript