Repository: FlowiseAI/Flowise
File: packages/components/src/httpSecurity.ts (TypeScript)

Code before:

        // Handle method changes for redirects according to HTTP specs
        if (response.status === 301 || response.status === 302 || response.status === 303) {
            // For 303, or when redirecting POST/PUT/PATCH requests, change to GET
            if (response.status === 303 || (currentInit.method && ['POST', 'PUT', 'PATCH'].includes(currentInit.method.toUpperCase()))) {
                currentInit = {
                    ...currentInit,
                    method: 'GET',
                    body: undefined
                }
            }
        }
    }

    throw new Error('Too many redirects')
}

type ResolvedTarget = {
    hostname: string
    ip: string
    family: 4 | 6
    protocol: 'http' | 'https'
}

async function resolveAndValidate(url: string): Promise<ResolvedTarget> {
    const denyListString = process.env.HTTP_DENY_LIST
    if (!denyListString) {
        throw new Error('HTTP_DENY_LIST must be set for secure requests')
    }

    const denyList = denyListString.split(',').map((s) => s.trim())
    const u = new URL(url)
    const hostname = u.hostname
    const protocol = u.protocol === 'https:' ? 'https' : 'http'

    if (ipaddr.isValid(hostname)) {
        isDeniedIP(hostname, denyList)
        return { hostname, ip: hostname, family: hostname.includes(':') ? 6 : 4, protocol }
    }

    const records = await dns.lookup(hostname, { all: true })
    if (records.length === 0) {
        throw new Error(`DNS resolution failed for ${hostname}`)
    }

    for (const r of records) {
        isDeniedIP(r.address, denyList)
    }

    const chosen = records.find((r) => r.family === 4) ?? records[0]


Review comment (suggestion):
By forcing every users to specify `HTTP_DENY_LIST`, its not user/begineer friendly.

The decision we took is to allow users to have the option to specify if needed, otherwise its not blocking by default. Its not secured by default. We have also documented [here](https://docs.flowiseai.com/configuration/environment-variables#recommended-production-settings)


Code after:

        // Handle method changes for redirects according to HTTP specs
        if (response.status === 301 || response.status === 302 || response.status === 303) {
            // For 303, or when redirecting POST/PUT/PATCH requests, change to GET
            if (response.status === 303 || (currentInit.method && ['POST', 'PUT', 'PATCH'].includes(currentInit.method.toUpperCase()))) {
                currentInit = {
                    ...currentInit,
                    method: 'GET',
                    body: undefined
                }
            }
        }
    }

    throw new Error('Too many redirects')
}

type ResolvedTarget = {
    hostname: string
    ip: string
    family: 4 | 6
    protocol: 'http' | 'https'
}

async function resolveAndValidate(url: string): Promise<ResolvedTarget> {
    const denyListString = process.env.HTTP_DENY_LIST
    const denyList = denyListString ? denyListString.split(',').map((s) => s.trim()) : null

    const u = new URL(url)
    const hostname = u.hostname
    const protocol: 'http' | 'https' = u.protocol === 'https:' ? 'https' : 'http'

    if (ipaddr.isValid(hostname)) {
        if (denyList) {
            isDeniedIP(hostname, denyList)
        }

        return {
            hostname,
            ip: hostname,
            family: hostname.includes(':') ? 6 : 4,
            protocol
        }
    }

    const records = await dns.lookup(hostname, { all: true })
    if (records.length === 0) {
        throw new Error(`DNS resolution failed for ${hostname}`)
    }

    if (denyList) {