Open-Source Wikis

/

Bitwarden Server

/

Apps

/

Icons

bitwarden/server

Icons

Active contributors: platform team.

Purpose

src/Icons/ is a stateless favicon proxy that fetches and caches website icons used by clients to decorate cipher entries (the small site logo next to a login). It exists as a separate service because:

  1. Client-side icon fetching leaks DNS to the user's network (privacy concern).
  2. CDN caching at this single endpoint reduces upstream traffic.
  3. Some sites block direct browser-extension fetches; the server-side proxy normalises the result.

Directory layout

src/Icons/
├── Program.cs / Startup.cs
├── Controllers/
│   └── IconsController.cs       # GET /{domain}/icon.png
├── Services/
│   ├── DomainMappingService.cs  # Normalises e.g. "www.example.com" → "example.com"
│   ├── IconFetchingService.cs   # Resolves DNS, fetches, falls back to /favicon.ico
│   ├── IconLinkService.cs       # Parses HTML for <link rel="icon"> hints
│   └── ...
├── Util/                        # MIME / image helpers
├── Models/                      # IconResult, IconHttpRequest
├── Resources/                   # Default fallback icon
├── IconsSettings.cs             # Config: timeouts, allowed schemes
├── appsettings.*.json
└── Dockerfile / build.sh / entrypoint.sh

Key abstractions

Type Path Description
Startup src/Icons/Startup.cs MVC + IDistributedCache + the icon services. Disables auth (this is a public service).
IconsController src/Icons/Controllers/IconsController.cs Public GET /{domain}/icon.png. Returns the cached icon, the discovered icon, or a built-in fallback.
IconFetchingService src/Icons/Services/IconFetchingService.cs Coordinates DNS resolution, HTTP fetch (with strict timeouts), HTML parse for <link rel="icon">, and final /favicon.ico fallback.
DomainMappingService src/Icons/Services/DomainMappingService.cs Strips subdomains, lowercases, and validates the input is a real DNS name (not an IP, port, or path).
IDistributedCache (registered in Startup) Caches icon bytes per domain with a TTL controlled by IconsSettings.

How it works

sequenceDiagram
    participant Ext as Browser Extension
    participant Icons
    participant Cache as IDistributedCache
    participant Site as 3rd party site

    Ext->>Icons: GET /github.com/icon.png
    Icons->>Cache: lookup github.com
    alt cache hit
        Cache-->>Icons: bytes
    else cache miss
        Icons->>Site: DNS + HTTP GET https://github.com/
        Icons->>Icons: parse <link rel="icon">
        Icons->>Site: GET <icon URL>
        Icons->>Cache: store
    end
    Icons-->>Ext: PNG bytes

Because it is unauthenticated and CDN-fronted, the production deployment puts a long edge cache in front of it.

Integration points

  • No database — Icons is fully stateless. Cache lives in IDistributedCache (Redis cloud / in-memory dev).
  • No identity — public anonymous service.
  • Self-host — included in the bundled stack and reachable as /icons/* via the nginx reverse proxy.

Security notes

  • DNS resolution is restricted to public addresses; the service refuses to fetch RFC1918 / link-local / loopback IPs (SSRF mitigation).
  • Strict request timeouts prevent slow-loris attackers from exhausting the connection pool.
  • The fetched content is re-encoded to a normalised PNG before being returned.

Entry points for modification

  • Add a new image format → extend the converters in src/Icons/Util/ and update IconResult content negotiation.
  • Tighten SSRF rules → edit IconFetchingService host-validation logic.
  • Change the cache TTL → adjust IconsSettings and the registered DistributedCacheEntryOptions.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Icons – Bitwarden Server wiki | Factory