Kareadita/Kavita · error · KavitaException

url-blocked-address

Error message

url-blocked-address

What it means

Thrown by FlurlConfiguration.CreateSafeRequest's ConnectCallback after every resolved IP for the target host was either blocked by IpBlocklist (loopback, private, reserved, CGNAT, link-local, multicast ranges) or failed its TCP connect. This is Kavita's SSRF guard preventing requests to internal/private addresses, so it surfaces as HTTP 500 with 'url-blocked-address'.

Source

Thrown at Kavita.Common/Helpers/FlurlConfiguration.cs:88

                        foreach (var addr in addresses)
                        {
                            if (IpBlocklist.IsBlockedAddress(addr)) continue;

                            var socket = new Socket(addr.AddressFamily, SocketType.Stream, ProtocolType.Tcp);
                            try
                            {
                                await socket.ConnectAsync(new IPEndPoint(addr, context.DnsEndPoint.Port), ct);
                                return new NetworkStream(socket, ownsSocket: true);
                            }
                            catch
                            {
                                socket.Dispose();
                                continue;
                            }
                        }


                        throw new KavitaException("url-blocked-address");
                    }
                };

                var httpClient = new HttpClient(handler);
                client = new FlurlClient(httpClient);
                SafeClients[key] = client;
            }

            return client.Request(url);
        }
    }
}

View on GitHub (pinned to 9c3e540000)

Solutions

  1. Use a public hostname/IP that resolves to a routable address — the blocklist rejects private ranges by design.
  2. If you control the source data, validate the URL is public before handing it to CreateSafeRequest.
  3. If the target is legitimately internal and trusted, use ConfigureClientForUrl (no SSRF check) only for hardcoded trusted hosts, never user input.
  4. Fix the target host connectivity if the real problem is refused connections rather than blocked IPs.

Example fix

// before
var req = FlurlConfiguration.CreateSafeRequest("http://192.168.1.5/cover.jpg");

// after
var req = FlurlConfiguration.CreateSafeRequest("https://cdn.example.com/cover.jpg");
Defensive patterns

Strategy: try-catch

Validate before calling

var uri = new Uri(url);
foreach (var addr in await Dns.GetHostAddressesAsync(uri.Host))
    if (IpBlocklist.IsBlockedAddress(addr))
        throw new InvalidOperationException("URL resolves to a blocked address");

Try / catch

try { var resp = await FlurlConfiguration.CreateSafeRequest(url).GetAsync(); }
catch (KavitaException ex) when (ex.Message == "url-blocked-address")
{ /* surface to user: pick a public URL */ }

Prevention

When it happens

Trigger: A user-supplied or external URL resolves only to private/reserved IPs (e.g. 127.0.0.1, 10.x, 192.168.x, ::1), or DNS rebinding points a public hostname at an internal IP, or every resolved address refused the connection. Triggered by cover upload-by-url, any Flurl CreateSafeRequest call against such a host.

Common situations: Testing against localhost/lan URLs; a misconfigured cover/book image URL that points at an internal host; DNS rebinding attack; the target host is genuinely unreachable (all IPs fail connect) so the blocklist-or-connect loop exhausts.

Related errors


AI-assisted analysis of Kareadita/Kavita@9c3e540000 (2026-08-13). Data as JSON: /api/errors/22a0c648d91cdfa5. Report an issue: GitHub.