Kareadita/Kavita · warning · KavitaException

url-https-only

Error message

url-https-only

What it means

Thrown by UrlValidationService.ValidateUrlAsync when the parsed URI's scheme is not https (case-insensitive). Kavita forbids plain http:// (and any non-https scheme) for user-supplied URLs as part of its SSRF/transport-security posture. It is a localized KavitaException surfaced as HTTP 500 (or 400 where callers catch it).

Source

Thrown at Kavita.Services/UrlValidationService.cs:22

using System.Threading.Tasks;
using Kavita.API.Services;
using Kavita.Common;
using Kavita.Common.Helpers;

namespace Kavita.Services;

public class UrlValidationService(ILocalizationService localizationService) : IUrlValidationService
{
    public async Task ValidateUrlAsync(string url)
    {
        if (!Uri.TryCreate(url, UriKind.Absolute, out var uri))
        {
            throw new KavitaException(await localizationService.TranslateAsync("url-malformed"));
        }

        if (!string.Equals(uri.Scheme, "https", StringComparison.OrdinalIgnoreCase))
        {
            throw new KavitaException(await localizationService.TranslateAsync("url-https-only"));
        }

        IPAddress[] addresses;
        try
        {
            addresses = await Dns.GetHostAddressesAsync(uri.Host);
        }
        catch (SocketException)
        {
            throw new KavitaException(await localizationService.TranslateAsync("url-unable-to-resolve"));
        }

        if (addresses.Length == 0)
        {
            throw new KavitaException(await localizationService.TranslateAsync("url-unable-to-resolve"));
        }

        foreach (var address in addresses)

View on GitHub (pinned to 9c3e540000)

Solutions

  1. Upgrade the URL to https:// on the client before submitting when the target supports TLS.
  2. Reject non-https input in the form (`new URL(url).protocol === 'https:'`).
  3. If the target truly has no TLS, host the asset on an https endpoint (e.g., put it behind Kavita's own TLS or a reverse proxy).

Example fix

// before
const url = input; // user may type http://
// after
let url = input.trim();
if (url.startsWith('http://')) url = 'https://' + url.slice('http://'.length);
Defensive patterns

Strategy: validation

Validate before calling

function isHttpsUrl(url: string): boolean {
  try { return new URL(url.trim()).protocol === 'https:'; } catch { return false; }
}

Type guard

function isHttpsString(s: unknown): s is string {
  return typeof s === 'string' && isHttpsUrl(s);
}

Try / catch

try { await svc.fetchFromUrl(url); } catch (e) { if (/https/i.test(e.message)) showUser('Only https:// URLs are allowed'); else throw e; }

Prevention

When it happens

Trigger: ValidateUrlAsync receives an absolute URI whose scheme is http, ftp, file, etc. Reachable from all the same callers as error 195 (cover/favicon/font/CBL/upload-by-url).

Common situations: User pastes an http:// image host; a self-hosted resource is only reachable over http; a config field defaulted to http; an internal service without TLS is referenced.

Related errors


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