FlowiseAI/Flowise · critical · Error

Access to this host is denied by policy.

Error message

Access to this host is denied by policy.

What it means

Thrown by isDeniedIP() when the resolved IP matches a CIDR range in the deny list (e.g. 10.0.0.0/8, 127.0.0.0/8, 169.254.169.254 metadata-service range). This is the SSRF protection layer: it prevents the application from making outbound requests to private, loopback, link-local, or cloud-metadata endpoints. The deny list defaults to RFC1918 ranges plus cloud-metadata IPs.

Source

Thrown at packages/components/src/httpSecurity.ts:85

    }

    for (const entry of denyList) {
        if (entry.includes('/')) {
            try {
                const [rangeAddr, mask] = ipaddr.parseCIDR(entry)
                let parsedRange = rangeAddr
                let adjustedMask = mask

                // Also normalize deny list entries
                if (parsedRange.kind() === 'ipv6' && (parsedRange as ipaddr.IPv6).isIPv4MappedAddress()) {
                    if (mask < 96) continue // malformed IPv4-mapped CIDR — skip
                    parsedRange = (parsedRange as ipaddr.IPv6).toIPv4Address()
                    adjustedMask -= 96
                }

                if (parsedIp.kind() === parsedRange.kind()) {
                    if (parsedIp.match(parsedRange, adjustedMask)) {
                        throw new Error('Access to this host is denied by policy.')
                    }
                }
            } catch (error) {
                throw new Error(`isDeniedIP: ${error}`)
            }
        } else {
            // Try to parse and normalize the deny list entry for consistent comparison
            // This handles non-canonical IPv6 addresses (e.g., FE80::1, 2001:0DB8::1)
            if (ipaddr.isValid(entry)) {
                let parsedEntry = ipaddr.parse(entry)

                // Normalize IPv4-mapped IPv6 entries
                if (parsedEntry.kind() === 'ipv6' && (parsedEntry as ipaddr.IPv6).isIPv4MappedAddress()) {
                    parsedEntry = (parsedEntry as ipaddr.IPv6).toIPv4Address()
                }

                // Compare normalized forms
                if (parsedIp.toString() === parsedEntry.toString()) {

View on GitHub (pinned to abe4a8601a)

Solutions

  1. If the request is legitimate and internal, set HTTP_SECURITY_CHECK=false and use HTTP_DENY_LIST to allow only the specific internal host while keeping other protections.
  2. Pre-resolve and validate the target host before queueing the request, surfacing a clear user-facing error.
  3. Ensure the URL the user supplied is validated against an allowlist rather than a denylist for high-risk features.
  4. Do not disable security globally; scope the relaxation to the specific integration via HTTP_DENY_LIST overrides.

Example fix

// before
await secureFetch(userSuppliedUrl) // userSuppliedUrl resolves to 10.0.0.5

// after
// allow only a specific internal CIDR while keeping default protections elsewhere
process.env.HTTP_SECURITY_CHECK = 'false'
process.env.HTTP_DENY_LIST = '169.254.169.254,127.0.0.0/8' // narrow deny list
await secureFetch(userSuppliedUrl)
Defensive patterns

Strategy: validation

Validate before calling

// Resolve the target and check against the deny list before the real request
import { checkDenyList } from './httpSecurity'

async function preCheck(url: string) {
  try {
    await checkDenyList(url)
    return { ok: true }
  } catch (e) {
    return { ok: false, reason: String(e) }
  }
}

const status = await preCheck(targetUrl)
if (!status.ok) throw new Error(`Blocked: ${status.reason}`)

Try / catch

try {
  return await secureFetch(url, init)
} catch (e) {
  if (String(e).includes('denied by policy')) {
    // do not retry; surface a permission error to the caller
    throw new ForbiddenError(`URL not allowed: ${url}`)
  }
  throw e
}

Prevention

When it happens

Trigger: The target URL's hostname resolves to an IP within a denied CIDR. Concretely: a request to a URL whose DNS resolves to 10.x.x.x, 127.x.x.x, 169.254.x.x, 172.16-31.x.x, 192.168.x.x, or an IPv6 private/link-local range. The CIDR match at line 84 fires after both the request IP and the CIDR entry are normalized.

Common situations: User-supplied URLs in an AI agent tool that the server then fetches (SSRF attack surface). Internal monitoring that legitimately needs to reach a private host. A public hostname that has an A record pointing at a private IP (DNS rebinding). Cloud functions reaching 169.254.169.254 for instance metadata. Testing against localhost.

Related errors


AI-assisted analysis of FlowiseAI/Flowise@abe4a8601a (2026-08-12). Data as JSON: /api/errors/b84fc0b779b94a30. Report an issue: GitHub.