CVE-2019-11069: Improper Input Validation (CWE-20)
value: Sequelize version 5 before 5.3.0 does not properly ensure that standard conforming strings are used.
CWE description: The product receives input or data, but it does
        not validate or incorrectly validates that the input has the
        properties that are required to process the data safely and
        correctly.
CVSS v3 base score: 7.5
Published: 2019-04-10T21:29Z
Repository: https://github.com/sequelize/sequelize
Language: JavaScript
Files changed: lib/dialects/abstract/connection-manager.js, lib/dialects/postgres/connection-manager.js
Commit date: 2019-04-10 16:25:43 +0530
Commit message: feat(postgres): enable standard conforming strings when required (#10746)


Diff: diff --git a/lib/dialects/abstract/connection-manager.js b/lib/dialects/abstract/connection-manager.js
index c3e1b9eef..9d26e73d1 100644
--- a/lib/dialects/abstract/connection-manager.js
+++ b/lib/dialects/abstract/connection-manager.js
@@ -254,11 +254,14 @@ class ConnectionManager {
 
             //connection might have set databaseVersion value at initialization,
             //avoiding a useless round trip
             if (this.sequelize.options.databaseVersion === 0) {
               return this.sequelize.databaseVersion(_options).then(version => {
-                this.sequelize.options.databaseVersion = semver.valid(version) ? version : this.defaultVersion;
+                const parsedVersion = _.get(semver.coerce(version), 'version') || version;
+                this.sequelize.options.databaseVersion = semver.valid(parsedVersion)
+                  ? parsedVersion
+                  : this.defaultVersion;
                 this.versionPromise = null;
                 return this._disconnect(connection);
               });
             }
 
diff --git a/lib/dialects/postgres/connection-manager.js b/lib/dialects/postgres/connection-manager.js
index e23450731..d847c78a0 100644
--- a/lib/dialects/postgres/connection-manager.js
+++ b/lib/dialects/postgres/connection-manager.js
@@ -120,10 +120,27 @@ class ConnectionManager extends AbstractConnectionManager {
 
     return new Promise((resolve, reject) => {
       let responded = false;
 
       const connection = new this.lib.Client(connectionConfig);
+
+      const parameterHandler = message => {
+        switch (message.parameterName) {
+          case 'server_version':
+            if (this.sequelize.options.databaseVersion === 0) {
+              const version = semver.coerce(message.parameterValue).version;
+              this.sequelize.options.databaseVersion = semver.valid(version)
+                ? version
+                : this.defaultVersion;
+            }
+            break;
+          case 'standard_conforming_strings':
+            connection['standard_conforming_strings'] = message.parameterValue;
+            break;
+        }
+      };
+
       const endHandler = () => {
         debug('connection timeout');
         if (!responded) {
           reject(new sequelizeErrors.ConnectionTimedOutError(new Error('Connection timed out')));
         }
@@ -131,12 +148,23 @@ class ConnectionManager extends AbstractConnectionManager {
 
       // If we didn't ever hear from the client.connect() callback the connection timeout
       // node-postgres does not treat this as an error since no active query was ever emitted
       connection.once('end', endHandler);
 
+      if (!this.sequelize.config.native) {
+        // Receive various server parameters for further configuration
+        connection.connection.on('parameterStatus', parameterHandler);
+      }
+
       connection.connect(err => {
         responded = true;
+
+        if (!this.sequelize.config.native) {
+          // remove parameter handler
+          connection.connection.removeListener('parameterStatus', parameterHandler);
+        }
+
         if (err) {
           if (err.code) {
             switch (err.code) {
               case 'ECONNREFUSED':
                 reject(new sequelizeErrors.ConnectionRefusedError(err));
@@ -164,15 +192,11 @@ class ConnectionManager extends AbstractConnectionManager {
         }
       });
     }).tap(connection => {
       let query = '';
 
-      if (
-        this.sequelize.options.databaseVersion !== 0
-        && semver.gte(this.sequelize.options.databaseVersion, '8.2.0')
-        && semver.lt(this.sequelize.options.databaseVersion, '9.1.0')
-      ) {
+      if (connection['standard_conforming_strings'] !== 'on') {
         // Disable escape characters in strings
         // see https://github.com/sequelize/sequelize/issues/3545 (security issue)
         // see https://www.postgresql.org/docs/current/static/runtime-config-compatible.html#GUC-STANDARD-CONFORMING-STRINGS
         query += 'SET standard_conforming_strings=on;';
       }

Vulnerable code:                 this.sequelize.options.databaseVersion = semver.valid(version) ? version : this.defaultVersion;
      if (
        this.sequelize.options.databaseVersion !== 0
        && semver.gte(this.sequelize.options.databaseVersion, '8.2.0')
        && semver.lt(this.sequelize.options.databaseVersion, '9.1.0')
      ) {
Fixed code:                 const parsedVersion = _.get(semver.coerce(version), 'version') || version;
                this.sequelize.options.databaseVersion = semver.valid(parsedVersion)
                  ? parsedVersion
                  : this.defaultVersion;

      const parameterHandler = message => {
        switch (message.parameterName) {
          case 'server_version':
            if (this.sequelize.options.databaseVersion === 0) {
              const version = semver.coerce(message.parameterValue).version;
              this.sequelize.options.databaseVersion = semver.valid(version)
                ? version
                : this.defaultVersion;
            }
            break;
          case 'standard_conforming_strings':
            connection['standard_conforming_strings'] = message.parameterValue;
            break;
        }
      };

      if (!this.sequelize.config.native) {
        // Receive various server parameters for further configuration
        connection.connection.on('parameterStatus', parameterHandler);
      }


        if (!this.sequelize.config.native) {
          // remove parameter handler
          connection.connection.removeListener('parameterStatus', parameterHandler);
        }

      if (connection['standard_conforming_strings'] !== 'on') {