{"record":{"id":"46c9042a46a4d972","repo":"Kareadita/Kavita","slug":"font-url-not-allowed","errorCode":null,"errorMessage":"font-url-not-allowed","messagePattern":"font-url-not-allowed","errorType":"exception","errorClass":"KavitaException","httpStatus":null,"severity":"warning","filePath":"Kavita.Services/FontService.cs","lineNumber":166,"sourceCode":"\n        await ResetFamilyReferences(family);\n\n        foreach (var file in files)\n        {\n            MoveFontFileToTemp(file);\n            unitOfWork.EpubFontRepository.Remove(file);\n        }\n\n        await unitOfWork.CommitAsync(ct);\n\n        return new FontDeleteResultDto {Deleted = true, InUse = inUse};\n    }\n\n    public async Task<EpubFont[]> CreateFontsFromUrl(string url, CancellationToken ct = default)\n    {\n        if (!url.StartsWith(SupportedFontUrlPrefix))\n        {\n            throw new KavitaException(\"font-url-not-allowed\");\n        }\n\n        // Extract Font name from url\n        var fontFamily = url.Split(SupportedFontUrlPrefix)[1].Split(\"?\")[0].Split(\"/\").Last();\n        logger.LogInformation(\"Preparing to download {FontName} font\", fontFamily.Sanitize());\n\n        var metaData = await GetGoogleFontsMetadataAsync(fontFamily);\n        if (metaData == null)\n        {\n            logger.LogError(\"Unable to find metadata for {FontName}\", fontFamily.Sanitize());\n            throw new KavitaException(\"errors.font-not-found\");\n        }\n\n        // Choose the variable font if available\n        // Otherwise take the full list.\n        // This should be fine since Google Fonts seems to\n        // only prepend filenames with 'static/' for font\n        // families that have variable fonts since the","sourceCodeStart":148,"sourceCodeEnd":184,"githubUrl":"https://github.com/Kareadita/Kavita/blob/9c3e5400007f8a0282f7d883f2ad5e71716e514d/Kavita.Services/FontService.cs#L148-L184","documentation":"Thrown by FontService.CreateFontsFromUrl when the provided URL does not start with the required prefix 'https://fonts.google.com/'. This is a security and validation guard — only Google Fonts URLs are accepted for automatic font download. The check is a simple StartsWith comparison with the hardcoded constant.","triggerScenarios":"User pastes a direct font file URL (e.g., .woff2 link) instead of a Google Fonts family page; user uses http:// instead of https://; user submits a URL from another font provider (Font Squirrel, Adobe Fonts); URL has leading whitespace or an unexpected scheme.","commonSituations":"User misunderstands the required URL format; user attempts to use a self-hosted font URL; URL is copied from a browser that stripped the protocol or added a trailing path; typo in the URL scheme.","solutions":["Use a valid Google Fonts URL in the format: https://fonts.google.com/<family-name>","Ensure the URL starts with exactly 'https://fonts.google.com/' (note the trailing slash)","For non-Google fonts, use the manual upload feature (CreateFontFromFileAsync) instead of the URL method","Trim leading/trailing whitespace from the URL before submission"],"exampleFix":"// Correct URL format:\n// https://fonts.google.com/css2?family=Roboto\n// or simply:\n// https://fonts.google.com/Roboto\n\n// Client-side validation:\n// if (!url.startsWith('https://fonts.google.com/')) {\n//   toast.error('Only Google Fonts URLs (https://fonts.google.com/...) are supported');\n//   return;\n// }","handlingStrategy":"validation","validationCode":"// Validate URL prefix before calling CreateFontsFromUrl:\n// const prefix = 'https://fonts.google.com/';\n// if (!url || !url.startsWith(prefix)) {\n//     return BadRequest($\"Only Google Fonts URLs starting with '{prefix}' are supported.\");\n// }\n// url = url.trim(); // sanitize whitespace","typeGuard":null,"tryCatchPattern":"// try {\n//     var fonts = await fontService.CreateFontsFromUrl(url, ct);\n//     return Ok(fonts);\n// } catch (KavitaException ex) when (ex.Message == \"font-url-not-allowed\") {\n//     return BadRequest(new { error = \"Only Google Fonts URLs (https://fonts.google.com/...) are allowed.\" });\n// }","preventionTips":["Implement client-side URL validation with the exact required prefix before submission","Provide a link to Google Fonts in the UI so users browse and copy URLs from the correct source","Trim whitespace from the URL before validation to avoid false negatives","For non-Google fonts, direct users to the manual upload feature instead"],"tags":["font","url-validation","google-fonts","security","input-validation"],"backgroundTag":null,"analyzedSha":"9c3e5400007f8a0282f7d883f2ad5e71716e514d","analyzedAt":"2026-08-13T19:06:05.897Z","schemaVersion":2},"datasetVersion":"2026-08-13T19:17:28.613Z"}