xml2json-unsafe-deserialization

Try in Playground
javascript-expressjsSecurityError

0

No tags

CWE-502

Make sure that the data passed to deserialized is a string and not an object or any other data type the XML to JSON is not expecting. This avoids the deserialization of untrusted data, as mentioned by CWE-502.

Ast Rule: function call


xml2json-unsafe-deserialization

How to write a rule
// Function to check that a module with name moduleName is imported into variable variableName
function isModuleImported(node, variableName, moduleName) {
  // Get all the assignments and check to get an assignment like
  // const variableName = require("moduleName");
  const n = node.context.assignments.filter(a => a.left && a.left.astType === "string" && a.left.value === variableName);
  if(n && n.length > 0 ){
    const call = n[0].right;
    if(call.astType === "functioncall" && call.arguments && call.arguments.values && call.arguments.values.length > 0) {
      const arg = call.arguments.values[0].value;

      if(arg.astType === "string" && (arg.value === `"${moduleName}"` || arg.value === `'${moduleName}'`)) {
        return true;
      }
    }
  }
  return false;
}

function isValueString(value) {
  if(!value){
    return false;
  }
  const stringChar = ['"', "'", "`"];


  if (value && value.length > 2){
    return stringChar.some(v => {
      if(value.charAt(value.length-1) === v && value.charAt(0) === v) {
        return true;
      }
    });
    
  }
  return false;
}

// Function to check that a module with name moduleName is imported into variable variableName
function getVariableString(node, variableName) {
  // Get all the assignments and check to get an assignment like
  // const variableName = require("moduleName");
  const n = node.context.assignments.filter(a => a.left && a.left.astType === "string" && a.left.value === variableName);
  if(n && n.length > 0 ){
    const right = n[0].right;
    if(right.astType === "string") {
      return right.value;
    }
  }
  return null;
}
                        

// main entrypoint
function visit(node) {  
  const functionName = node.functionName;

  // the function name called is a member that has a parent and a name.
  // Ideally, the name is toJson and the parent is a variable that imports 
  // the "xml2json" module.
  if(functionName && functionName.astType === "member" && functionName.name.value === "toJson"){
    if(functionName.parent && functionName.parent.astType === "string") {
      const parentName = functionName.parent.value;
      const isUsingModule = isModuleImported(node, parentName, "xml2json");
      const firstArgument = node.arguments && node.arguments && node.arguments.values && node.arguments.values[0];
      const isFirstArgumentString = isValueString(firstArgument.value.value) || isValueString(getVariableString(node, firstArgument.value.value));

      if(isUsingModule && !isFirstArgumentString) {
        const error = buildError(node.functionName.start.line, node.functionName.start.col, node.functionName.end.line, node.functionName.end.col, "unsafe deserialization", "CRITICAL", "SAFETY");
        addError(error);
      }
    }
  }
}

xml2json-use.js

Expected test result: has error

function test1(body) {
  const xml2json = require('xml2json')
  const result = xml2json.toJson(body, { object: true, arrayNotation: true })
  return result
}

xml2json-no-error.js

Expected test result: no error

const xml2json = require('xml2json')
const content = "<xml></xml>";
xml2json.toJson(content, { object: true, arrayNotation: true })

xml2json-no-error2.js

Expected test result: no error

const xml2json = require('xml2json')
xml2json.toJson("<xml></xml>", { object: true, arrayNotation: true })
Add comment

Log in to add a comment


    Be the first one to leave a comment!

Codiga Logo
Codiga Hub
  • Rulesets
  • Playground
  • Snippets
  • Cookbooks
soc-2 icon

We are SOC-2 Compliance Certified

G2 high performer medal

Codiga – All rights reserved 2022.