CVE-2022-2900 (JavaScript)

The parse-url library is vulnerable to server-side request forgery when it is given attacker-controlled URL strings that are malformed or ambiguous but still contain network destinations. In the vulnerable behavior, URLs that the underlying parser cannot reliably interpret may still be returned to callers as usable parsed URL objects, exposing schemes, hosts, paths, or original href values that can represent loopback, private, link-local, metadata-service, or other internal targets. Applications that rely on parse-url output for URL validation or request routing can therefore be tricked into accepting or requesting attacker-chosen internal resources.

Weakness:
CWE-918: name: Server-Side Request Forgery (SSRF)
description: The web server receives a URL or similar request from an upstream component and retrieves the contents of this URL, but it does not sufficiently ensure that the request is being sent to the expected destination.

Repository: https://github.com/ionicabizau/parse-url

Vulnerable code:
file_path: lib/index.js
snippet: const parseUrl = (url, normalize = false) => {

    // Constants
    const GIT_RE = /(^(git@|http(s)?:\/\/)([\w\.\-@]+)(\/|:))(([\~,\.\w,\-,\_,\/]+)(.git){0,1}((\/){0,1}))/

    if (typeof url !== "string" || !url.trim()) {
        const err = new Error("Invalid url.")
        err.subject_url = url
        throw err
    }

    if (normalize) {
        if (typeof normalize !== "object") {
            normalize = {
                stripHash: false
            }
        }
        url = normalizeUrl(url, normalize)
    }

    const parsed = parsePath(url)

    // Potential git-ssh urls
    if (parsed.protocol === "file") {
        const matched  = parsed.href.match(GIT_RE)
        if (matched) {
            parsed.protocols = ["ssh"]
            parsed.protocol = "ssh"
            parsed.resource = matched[4]
            parsed.host = matched[4]
            parsed.user = "git"
            parsed.pathname = `/${matched[6]}`
        }
    }

    return parsed;
}

Fixed code:
file_path: lib/index.js
snippet: const parseUrl = (url, normalize = false) => {

    // Constants
    const GIT_RE = /(^(git@|http(s)?:\/\/)([\w\.\-@]+)(\/|:))(([\~,\.\w,\-,\_,\/]+)(.git){0,1}((\/){0,1}))/

    const throwErr = msg => {
        const err = new Error(msg)
        err.subject_url = url
        throw err
    }

    if (typeof url !== "string" || !url.trim()) {
        throwErr("Invalid url.")
    }

    if (url.length > parseUrl.MAX_INPUT_LENGTH) {
        throwErr("Input exceeds maximum length. If needed, change the value of parseUrl.MAX_INPUT_LENGTH.")
    }

    if (normalize) {
        if (typeof normalize !== "object") {
            normalize = {
                stripHash: false
            }
        }
        url = normalizeUrl(url, normalize)
    }

    const parsed = parsePath(url)

    // Potential git-ssh urls
    if (parsed.parse_failed) {
        const matched  = parsed.href.match(GIT_RE)
        if (matched) {
            parsed.protocols = ["ssh"]
            parsed.protocol = "ssh"
            parsed.resource = matched[4]
            parsed.host = matched[4]
            parsed.user = "git"
            parsed.pathname = `/${matched[6]}`
            parsed.parse_failed = false
        } else {
            throwErr("URL parsing failed.")
        }
    }

    return parsed;
}

file_path: lib/index.js
snippet: parseUrl.MAX_INPUT_LENGTH = 2048