CVE-2017-20160: Other (NVD-CWE-Other)
value: A vulnerability was found in flitto express-param up to 0.x. It has been classified as critical. This affects an unknown part of the file lib/fetchParams.js. The manipulation leads to improper handling of extra parameters. It is possible to initiate the attack remotely. Upgrading to version 1.0.0 is able to address this issue. The identifier of the patch is db94f7391ad0a16dcfcba8b9be1af385b25c42db. It is recommended to upgrade the affected component. The identifier VDB-217149 was assigned to this vulnerability.
CWE description: NVD is only using a subset of CWE for mapping instead of the entire CWE, and the weakness type is not covered by that subset.
CVSS v3 base score: 9.8
Published: 2022-12-31T20:15Z
Repository: https://github.com/flitto/express-param
Language: JavaScript
Files changed: lib/fetchParams.js
Commit date: 2017-03-02 16:47:06 +0900
Commit message: feat: Improve fetchParams

* Add geo-info to extra options
* protect against HTTP Parameter Pollution attacks
* Add int, float type options for parameters

Diff: diff --git a/lib/fetchParams.js b/lib/fetchParams.js
index 1c71478..76e9c99 100644
--- a/lib/fetchParams.js
+++ b/lib/fetchParams.js
@@ -6,19 +6,25 @@ var TYPE_DELIMETER = ':'
   , PATH_REGEX = /^{[A-Za-z0-9_]+}$/
   , DEFAULT_VAL_DELIMETER = '|='
   , extraOption;
 
 function getValue(req, keyName) {
+  var value;
+
   if (req.params && req.params[keyName] !== undefined) {
-    return req.params[keyName];
+    value = req.params[keyName];
   } else if (req.body && req.body[keyName] !== undefined) {
-    return req.body[keyName];
+    value = req.body[keyName];
   } else if (req.query && req.query[keyName] !== undefined) {
-    return req.query[keyName];
-  } else {
-    return undefined;
+    value = req.query[keyName];
+  }
+
+  if (Array.isArray(value)) {
+    value = value[value.length - 1];
   }
+
+  return value;
 }
 
 function getPath(req, keyName) {
   return req.params[keyName];
 }
@@ -115,10 +121,21 @@ function getOptionalParams(req, option_expressions) {
       break;
     }
 
     val = getFunc(req, key);
 
+    var typeMap = {
+      int: parseInt,
+      float: parseFloat,
+      number: parseFloat
+    };
+
+    var idx = Object.keys(typeMap).indexOf(keyInfo.type);
+    if (idx >= 0) {
+      options[key] = typeMap[keyInfo.type](val);
+    }
+
     if (keyInfo.type === 'number') {
       if (val !== undefined && val !== '')
         options[key] = parseFloat(val);
       else if (keyInfo.defaultVal)
         options[key] = parseFloat(keyInfo.defaultVal);
@@ -176,11 +193,11 @@ function requiredParameter(req, required_expressions) {
     , getFunc
     , err
     , key
     , val;
 
-  for (var i = 0, li = required_expressions.length; i <li ; i++) {
+  for (var i = 0, li = required_expressions.length; i < li; i++) {
     var keyInfo;
     try {
       keyInfo = getRequiredKeyInfo(required_expressions[i]);
       key = keyInfo.keyName;
     } catch (e) {
@@ -194,17 +211,32 @@ function requiredParameter(req, required_expressions) {
       getFunc = getExtra;
     else
       getFunc = getValue;
 
     val = getFunc(req, key);
-    if (keyInfo.type === 'number') {
+
+    var typeMap = {
+      int: parseInt,
+      float: parseFloat,
+      number: parseFloat
+    };
+
+    var idx = Object.keys(typeMap).indexOf(keyInfo.type);
+    if (idx >= 0) {
       if (isNaN(val)) {
         err = new Error('The parameter value is not a number : ' + key);
         err.code = 400;
         break;
       }
-      options[key] = parseFloat(val);
+
+      if (keyInfo.type == 'int' && !_.isSafeInteger(val)) {
+        err = new Error('The parameter value is not a integer : ' + key);
+        err.code = 400;
+        break;
+      }
+
+      options[key] = typeMap[keyInfo.type](val);
     } else {
       options[key] = val;
     }
 
     if (!options[key]) {

Vulnerable code:     return req.params[keyName];
    return req.body[keyName];
    return req.query[keyName];
  } else {
    return undefined;
  for (var i = 0, li = required_expressions.length; i <li ; i++) {
    if (keyInfo.type === 'number') {
      options[key] = parseFloat(val);
Fixed code:   var value;

    value = req.params[keyName];
    value = req.body[keyName];
    value = req.query[keyName];
  }

  if (Array.isArray(value)) {
    value = value[value.length - 1];

  return value;
    var typeMap = {
      int: parseInt,
      float: parseFloat,
      number: parseFloat
    };

    var idx = Object.keys(typeMap).indexOf(keyInfo.type);
    if (idx >= 0) {
      options[key] = typeMap[keyInfo.type](val);
    }

  for (var i = 0, li = required_expressions.length; i < li; i++) {

    var typeMap = {
      int: parseInt,
      float: parseFloat,
      number: parseFloat
    };

    var idx = Object.keys(typeMap).indexOf(keyInfo.type);
    if (idx >= 0) {

      if (keyInfo.type == 'int' && !_.isSafeInteger(val)) {
        err = new Error('The parameter value is not a integer : ' + key);
        err.code = 400;
        break;
      }

      options[key] = typeMap[keyInfo.type](val);