VYPR
Critical severity9.8NVD Advisory· Published Jul 1, 2024· Updated Apr 15, 2026

CVE-2024-39309

CVE-2024-39309

Description

Parse Server is an open source backend that can be deployed to any infrastructure that can run Node.js. A vulnerability in versions prior to 6.5.7 and 7.1.0 allows SQL injection when Parse Server is configured to use the PostgreSQL database. The algorithm to detect SQL injection has been improved in versions 6.5.7 and 7.1.0. No known workarounds are available.

Affected packages

Versions sourced from the GitHub Security Advisory.

PackageAffected versionsPatched versions
parse-servernpm
< 6.5.76.5.7
parse-servernpm
>= 7.0.0, < 7.1.07.1.0

Patches

2
f332d5457760

fix: SQL injection when using Parse Server with PostgreSQL; fixes security vulnerability [GHSA-c2hr-cqg6-8j6r](https://github.com/parse-community/parse-server/security/advisories/GHSA-c2hr-cqg6-8j6r) (#9168)

2 files changed · +14 9
  • package.json+1 0 modified
    @@ -124,6 +124,7 @@
         "test:mongodb:4.4.13": "npm run test:mongodb --dbversion=4.4.13",
         "test:mongodb:5.3.2": "npm run test:mongodb --dbversion=5.3.2",
         "test:mongodb:6.0.2": "npm run test:mongodb --dbversion=6.0.2",
    +    "test:postgres:testonly": "cross-env PARSE_SERVER_TEST_DB=postgres PARSE_SERVER_TEST_DATABASE_URI=postgres://postgres:password@localhost:5432/parse_server_postgres_adapter_test_database npm run testonly",
         "posttest:mongodb": "mongodb-runner stop",
         "pretest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.3.2} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} mongodb-runner start",
         "testonly": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.3.2} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} TESTING=1 jasmine",
    
  • src/Adapters/Storage/Postgres/PostgresStorageAdapter.js+13 9 modified
    @@ -2614,16 +2614,16 @@ function isAnyValueRegexStartsWith(values) {
       });
     }
     
    -function createLiteralRegex(remaining) {
    +function createLiteralRegex(remaining: string) {
       return remaining
         .split('')
         .map(c => {
    -      const regex = RegExp('[0-9 ]|\\p{L}', 'u'); // Support all unicode letter chars
    +      const regex = RegExp('[0-9 ]|\\p{L}', 'u'); // Support all Unicode letter chars
           if (c.match(regex) !== null) {
    -        // don't escape alphanumeric characters
    +        // Don't escape alphanumeric characters
             return c;
           }
    -      // escape everything else (single quotes with single quotes, everything else with a backslash)
    +      // Escape everything else (single quotes with single quotes, everything else with a backslash)
           return c === `'` ? `''` : `\\${c}`;
         })
         .join('');
    @@ -2633,14 +2633,14 @@ function literalizeRegexPart(s: string) {
       const matcher1 = /\\Q((?!\\E).*)\\E$/;
       const result1: any = s.match(matcher1);
       if (result1 && result1.length > 1 && result1.index > -1) {
    -    // process regex that has a beginning and an end specified for the literal text
    +    // Process Regex that has a beginning and an end specified for the literal text
         const prefix = s.substring(0, result1.index);
         const remaining = result1[1];
     
         return literalizeRegexPart(prefix) + createLiteralRegex(remaining);
       }
     
    -  // process regex that has a beginning specified for the literal text
    +  // Process Regex that has a beginning specified for the literal text
       const matcher2 = /\\Q((?!\\E).*)$/;
       const result2: any = s.match(matcher2);
       if (result2 && result2.length > 1 && result2.index > -1) {
    @@ -2650,14 +2650,18 @@ function literalizeRegexPart(s: string) {
         return literalizeRegexPart(prefix) + createLiteralRegex(remaining);
       }
     
    -  // remove all instances of \Q and \E from the remaining text & escape single quotes
    +  // Remove problematic chars from remaining text
       return s
    +    // Remove all instances of \Q and \E
         .replace(/([^\\])(\\E)/, '$1')
         .replace(/([^\\])(\\Q)/, '$1')
         .replace(/^\\E/, '')
         .replace(/^\\Q/, '')
    -    .replace(/([^'])'/g, `$1''`)
    -    .replace(/^'([^'])/, `''$1`);
    +    // Ensure even number of single quote sequences by adding an extra single quote if needed;
    +    // this ensures that every single quote is escaped
    +    .replace(/'+/g, match => {
    +      return match.length % 2 === 0 ? match : match + "'";
    +    });
     }
     
     var GeoPointCoder = {
    
2edf1e4c0363

fix: SQL injection when using Parse Server with PostgreSQL; fixes security vulnerability [GHSA-c2hr-cqg6-8j6r](https://github.com/parse-community/parse-server/security/advisories/GHSA-c2hr-cqg6-8j6r) (#9167)

2 files changed · +14 9
  • package.json+1 0 modified
    @@ -125,6 +125,7 @@
         "test:mongodb:5.3.2": "npm run test:mongodb --dbversion=5.3.2",
         "test:mongodb:6.0.2": "npm run test:mongodb --dbversion=6.0.2",
         "test:mongodb:7.0.1": "npm run test:mongodb --dbversion=7.0.1",
    +    "test:postgres:testonly": "cross-env PARSE_SERVER_TEST_DB=postgres PARSE_SERVER_TEST_DATABASE_URI=postgres://postgres:password@localhost:5432/parse_server_postgres_adapter_test_database npm run testonly",
         "pretest": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.3.2} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} mongodb-runner start -t ${MONGODB_TOPOLOGY} --version ${MONGODB_VERSION} -- --port 27017",
         "testonly": "cross-env MONGODB_VERSION=${MONGODB_VERSION:=5.3.2} MONGODB_TOPOLOGY=${MONGODB_TOPOLOGY:=standalone} TESTING=1 jasmine",
         "test": "npm run testonly",
    
  • src/Adapters/Storage/Postgres/PostgresStorageAdapter.js+13 9 modified
    @@ -2614,16 +2614,16 @@ function isAnyValueRegexStartsWith(values) {
       });
     }
     
    -function createLiteralRegex(remaining) {
    +function createLiteralRegex(remaining: string) {
       return remaining
         .split('')
         .map(c => {
    -      const regex = RegExp('[0-9 ]|\\p{L}', 'u'); // Support all unicode letter chars
    +      const regex = RegExp('[0-9 ]|\\p{L}', 'u'); // Support all Unicode letter chars
           if (c.match(regex) !== null) {
    -        // don't escape alphanumeric characters
    +        // Don't escape alphanumeric characters
             return c;
           }
    -      // escape everything else (single quotes with single quotes, everything else with a backslash)
    +      // Escape everything else (single quotes with single quotes, everything else with a backslash)
           return c === `'` ? `''` : `\\${c}`;
         })
         .join('');
    @@ -2633,14 +2633,14 @@ function literalizeRegexPart(s: string) {
       const matcher1 = /\\Q((?!\\E).*)\\E$/;
       const result1: any = s.match(matcher1);
       if (result1 && result1.length > 1 && result1.index > -1) {
    -    // process regex that has a beginning and an end specified for the literal text
    +    // Process Regex that has a beginning and an end specified for the literal text
         const prefix = s.substring(0, result1.index);
         const remaining = result1[1];
     
         return literalizeRegexPart(prefix) + createLiteralRegex(remaining);
       }
     
    -  // process regex that has a beginning specified for the literal text
    +  // Process Regex that has a beginning specified for the literal text
       const matcher2 = /\\Q((?!\\E).*)$/;
       const result2: any = s.match(matcher2);
       if (result2 && result2.length > 1 && result2.index > -1) {
    @@ -2650,14 +2650,18 @@ function literalizeRegexPart(s: string) {
         return literalizeRegexPart(prefix) + createLiteralRegex(remaining);
       }
     
    -  // remove all instances of \Q and \E from the remaining text & escape single quotes
    +  // Remove problematic chars from remaining text
       return s
    +    // Remove all instances of \Q and \E
         .replace(/([^\\])(\\E)/, '$1')
         .replace(/([^\\])(\\Q)/, '$1')
         .replace(/^\\E/, '')
         .replace(/^\\Q/, '')
    -    .replace(/([^'])'/g, `$1''`)
    -    .replace(/^'([^'])/, `''$1`);
    +    // Ensure even number of single quote sequences by adding an extra single quote if needed;
    +    // this ensures that every single quote is escaped
    +    .replace(/'+/g, match => {
    +      return match.length % 2 === 0 ? match : match + "'";
    +    });
     }
     
     var GeoPointCoder = {
    

Vulnerability mechanics

Generated by null/stub on May 9, 2026. Inputs: CWE entries + fix-commit diffs from this CVE's patches. Citations validated against bundle.

References

7

News mentions

0

No linked articles in our index yet.