CVE-2020-7781 (JavaScript)

This affects the package connection-tester before 0.2.1. The injection point is located in line 15 in index.js. The following PoC demonstrates the vulnerability:

Weakness:
CWE-77: name: Improper Neutralization of Special Elements used in a Command ('Command Injection')
description: The product constructs all or part of a command using externally-influenced input from an upstream component, but it does not neutralize or incorrectly neutralizes special elements that could modify the intended command when it is sent to a downstream component.

Repository: https://github.com/skoranga/node-connection-tester

Vulnerable code:
file_path: index.js
snippet:     test: function ConnectionTester(host, port, callbackOrConnectTimeout, callback) {

        // for backward compatibility
        if (typeof callbackOrConnectTimeout === 'function') {
            console.log('deprecated: Please migrate to the new interface ConnectionTester\(host, port, timeout, callback\)');
            return testAsync(host, port, SOCKET_TIMEOUT, callbackOrConnectTimeout);
        }
        if (typeof callbackOrConnectTimeout === 'number') {
            if (callback) {
                return testAsync(host, port, callbackOrConnectTimeout, callback);
            } else {
                return testSync(host, port, callbackOrConnectTimeout);
            }
        }
        if (callbackOrConnectTimeout === undefined) {
            return testSync(host, port, SOCKET_TIMEOUT);
        }
    }

Fixed code:
file_path: index.js
snippet:     test: function ConnectionTester(host, port, connectTimeout, callback) {

        // validate host
        if (!isValidHostNameOrIP(host)) {
            console.error('[connection-tester] invalid host: ', host);
            host = undefined;
        }
        // validate port
        var originalPort = port;
        port = +port;
        if (!port || port < 0 || port > 65535) {
            console.error('[connection-tester] invalid port: ', originalPort);
            port = undefined;
        }

        if (typeof connectTimeout === 'function') {
            console.error('deprecated: Please migrate to the new interface ConnectionTester\(host, port, timeout, callback\)');
            callback = connectTimeout;
            connectTimeout = SOCKET_TIMEOUT;
        }
        if (connectTimeout === undefined) {
            connectTimeout = SOCKET_TIMEOUT;
        }

        if (typeof connectTimeout === 'number') {
            if (!port || !host) {
                var output = {
                    success: false,
                    error: 'invalid host/port'
                };

                if (callback) {
                    return callback(null, output);
                } else {
                    return output;
                }
            }
            if (callback) {
                return testAsync(host, port, connectTimeout, callback);
            } else {
                return testSync(host, port, connectTimeout);
            }
        }
    }

file_path: index.js
snippet: //source - http://stackoverflow.com/questions/106179/regular-expression-to-match-dns-hostname-or-ip-address
var ValidHostnameRegex = new RegExp("^(([a-zA-Z0-9]|[a-zA-Z0-9][a-zA-Z0-9\-]*[a-zA-Z0-9])\.)*([A-Za-z0-9]|[A-Za-z0-9][A-Za-z0-9\-]*[A-Za-z0-9])$");

function isValidHostNameOrIP(host) {
    return net.isIP(host) || ValidHostnameRegex.test(host);
}