Safe alternatives for eval() in JavaScript (safety scanners test)

64 views Asked by At

I have runned the safety scanner for my application and it says in general:

"eval() is a dangerous function that executes code with all the privileges of the caller sides. If you run eval() on a string that might be affected attackers, then you can run malicious code on the device user with rights to your web page/extension."

That is my code before

Date.createNewFormat = function(format) {
    console.log('format 22', format)
    var funcName = "format" + Date.formatFunctions.count++;
    Date.formatFunctions[format] = funcName;
    var code = "Date.prototype." + funcName + " = function() {return ";
    var special = false;
    var ch = "";
    for (var i = 0; i < format.length; ++i) {
        ch = format.charAt(i);
        if (!special && ch == "\\") {
            special = true;
        } else {
            if (special) {
                special = false;
                code += "'" + String.escape(ch) + "' + ";
            } else {
                code += Date.getFormatCode(ch);
            }
        }
    }
    eval(code.substring(0, code.length - 3) + ";}");
}

so changed eval for new Function and I don't know if that can fix error in the scanner test

var runFunction = new Function(code.substring(0, code.length - 3) + ";}");
runFunction();
1

There are 1 answers

3
Barmar On

Instead of constructing the format function as a string that you eval(), you can evaluate the format string when

Date.createNewFormat = function(format) {
    console.log('format 22', format)
    let funcName = "format" + Date.formatFunctions.count++;
    Date.formatFunctions[format] = funcName;
    let funcArray = [];
    for (let i = 0; i < format.length; ++i) {
        let ch = format[i];
        if (ch == "\\" && i < format.length-1) {
            // use next character literally and skip over it
            i++;
            funcArray.push(() => format[i]);
        } else {
            funcArray.push(Date.getFormatCode(ch));
        }
    }
    Date.prototype[funcName] = function() {
        return funcArray.map(f => f.call(this));
    }
}

You'll need to change Date.getFormatCode() so instead of returning code as strings, it returns functions. The functions should refer to this to access the Date object being formatted (as I assume your string versions do) and return the formatted value.