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:
- Client-side icon fetching leaks DNS to the user's network (privacy concern).
- CDN caching at this single endpoint reduces upstream traffic.
- 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.shKey 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 bytesBecause 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 updateIconResultcontent negotiation. - Tighten SSRF rules → edit
IconFetchingServicehost-validation logic. - Change the cache TTL → adjust
IconsSettingsand the registeredDistributedCacheEntryOptions.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.