Skip to content

fix: crash when favicon endpoint returns non-image response - #173

Merged
Strobotti merged 4 commits into
mainfrom
fix/favicon-non-image-crash
Jul 19, 2026
Merged

fix: crash when favicon endpoint returns non-image response#173
Strobotti merged 4 commits into
mainfrom
fix/favicon-non-image-crash

Conversation

@Strobotti

Copy link
Copy Markdown
Owner

Summary

Fixes a crash (nil pointer dereference) when the favicon fetcher receives non-image content (e.g. HTML error pages) from servers that don't serve a proper favicon.

Reproducible with: linkquisition "https://console.mistral.ai" (their /favicon.ico returns an nginx HTML page).

Changes

  1. Validate favicon responses (internal/favicon/favicon.go)

    • Reject responses with non-image/* Content-Type headers
    • Validate response body against known image magic bytes (PNG, JPEG, GIF, ICO, BMP, WebP, SVG)
    • Validate cached entries on read and evict invalid ones automatically
  2. Fix thread-safety in UI update (cmd/browser_picker.go)

    • Wrap img.Resource/img.Refresh() in fyne.Do() to prevent concurrent access from the favicon goroutine
    • Rename resource from "favicon.png" to "favicon" to avoid format assumption from extension
  3. Tests (internal/favicon/favicon_test.go)

    • Fix existing tests to set proper Content-Type headers on test servers
    • Add tests for HTML rejection, non-image data rejection, cache eviction, magic byte detection, and content-type parsing

Testing

  • All 18 favicon tests pass
  • Manual test: linkquisition "https://console.mistral.ai" no longer crashes (favicon gracefully falls back to placeholder)

The favicon fetcher now rejects non-image responses at two levels:

1. Content-Type header check — rejects responses that are clearly not
   images (e.g. text/html served by misconfigured servers)
2. Magic byte validation — verifies the response body starts with
   recognized image format signatures (PNG, JPEG, GIF, ICO, BMP, WebP,
   SVG)

Previously, servers returning HTML error pages (like nginx default
pages) for /favicon.ico would pass raw HTML to Fyne's image renderer,
causing XML parse errors and potential crashes.

The cache reader also validates stored data on read, automatically
evicting entries that don't pass the image format check (protecting
against previously cached invalid responses).
The fetchAndUpdateFavicon goroutine was updating img.Resource and
calling img.Refresh() directly from a background goroutine without
synchronization. This could cause a nil pointer dereference when Fyne's
renderer accessed the image concurrently.

Wrap the UI update in fyne.Do() to ensure it runs on the main thread.
Also rename the static resource from "favicon.png" to "favicon" to
avoid Fyne making incorrect format assumptions from the file extension.
Update existing test servers to set Content-Type: image/* headers,
matching the new validation requirements.

Add new test cases:
- TestFetcher_RejectsHTMLResponse: verifies HTML content-type is rejected
- TestFetcher_RejectsNonImageData: verifies non-image bytes are rejected
  even when server claims image content-type
- TestFetcher_CacheEvictsInvalidData: verifies invalid cached entries
  are evicted and fresh data is fetched
- TestIsImageData: table-driven tests for magic byte detection
- TestIsImageContentType: table-driven tests for content-type parsing
@Strobotti Strobotti self-assigned this Jul 19, 2026
- Reduce cyclomatic complexity by using a table-driven magic byte check
  with bytes.HasPrefix instead of individual if-statements (gocyclo)
- Extract GIF magic strings into the imageMagic table (goconst)
- Use direct return of strings.Contains for SVG check (staticcheck S1008)
@Strobotti
Strobotti merged commit b505329 into main Jul 19, 2026
7 checks passed
@Strobotti
Strobotti deleted the fix/favicon-non-image-crash branch July 19, 2026 09:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant