Freika/dawarich · warning · UrlValidatable::BlockedUrlError
URL must not embed credentials (user:pass@host)
Error message
URL must not embed credentials (user:pass@host)
What it means
Raised as BlockedUrlError when the URL embeds userinfo ('user:pass@host') and the instance is NOT self-hosted (DawarichSettings.self_hosted? is false, i.e. the cloud deployment). Basic-auth-in-URL credentials are a leakage risk (they end up in logs, referrers, error reports), so cloud refuses them; the source comment notes self-hosters legitimately use them for e.g. Immich behind nginx basic auth, which is why the check is environment-gated.
Source
Thrown at app/services/concerns/url_validatable.rb:72
IPAddr.new('fc00::/7') # IPv6 ULA
].freeze
private
def validate_integration_url!(url)
return if url.blank?
uri = URI.parse(url)
unless %w[http https].include?(uri.scheme)
raise BlockedUrlError, I18n.t('services.concerns.url_validatable.invalid_scheme', scheme: uri.scheme)
end
raise BlockedUrlError, I18n.t('services.concerns.url_validatable.host_required') if uri.host.blank?
# Cloud refuses URLs that embed credentials. Self-hosters legitimately
# use http://user:pass@host — homelab Immich behind nginx basic-auth
# is a real config we don't want to break.
if uri.userinfo.present? && !DawarichSettings.self_hosted?
raise BlockedUrlError, I18n.t('services.concerns.url_validatable.embedded_credentials')
end
ip = IPAddr.new(Resolv.getaddress(uri.host))
if blocked_ranges.any? { |range| range.include?(ip) }
raise BlockedUrlError, I18n.t('services.concerns.url_validatable.blocked_address')
end
rescue URI::InvalidURIError
raise BlockedUrlError, I18n.t('services.concerns.url_validatable.invalid_format')
rescue Resolv::ResolvError
raise BlockedUrlError, I18n.t('services.concerns.url_validatable.unresolvable_host', host: uri.host)
end
def blocked_ranges
if DawarichSettings.self_hosted?
ALWAYS_BLOCKED_RANGES
else
ALWAYS_BLOCKED_RANGES + CLOUD_ONLY_BLOCKED_RANGES
endView on GitHub (pinned to 97fad417c5)
Solutions
- Remove the credentials from the URL and configure auth the supported way (API key field / header-based auth for the integration).
- If you are running your own instance, confirm self_hosted? is true in DawarichSettings — then this check is skipped by design.
- Never paste user:pass URLs into cloud settings; rotate those credentials if you already did.
Example fix
# before (cloud instance) url = 'https://alice:hunter2@immich.example.com' # -> BlockedUrlError # after url = 'https://immich.example.com' # supply auth via the integration's API key configuration instead
Defensive patterns
Strategy: validation
Validate before calling
uri = URI.parse(url.to_s) uri.userinfo.nil? || DawarichSettings.self_hosted? # warn cloud users pre-save
Type guard
def credential_free_url?(s) URI.parse(s.to_s).userinfo.nil? rescue URI::InvalidURIError false end
Try / catch
begin
validate_integration_url!(url)
rescue BlockedUrlError => e
# strip user:pass@ and configure API-key auth instead
url = url.sub(%r{\A([a-z]+://)[^@/]+@}i, '\1')
retry
end Prevention
- Never put basic-auth credentials in integration URLs on hosted platforms; use the API key field.
- Strip userinfo before saving (regex sub) as a convenience normalization.
- Rotate any credentials that were pasted into cloud settings.
When it happens
Trigger: On the hosted/cloud deployment, saving an integration URL like 'https://alice:secret@immich.example.com'. The same URL works on a self-hosted instance. Also triggered when a user pastes a browser URL that still contains basic-auth credentials.
Common situations: Users migrating a self-hosted config (with embedded credentials) to the cloud offering, copying a URL straight out of a password manager or browser address bar that retains user:pass@, curl examples from homelab docs pasted verbatim.
Related errors
- Invalid URL scheme: %{scheme}
- URL resolves to a blocked address
- URL must include a host
- Invalid URL format
- Could not resolve hostname: %{host}
AI-assisted analysis of Freika/dawarich@97fad417c5 (2026-08-21).
Data as JSON: /api/errors/c0bc447523ae5795.
Report an issue: GitHub.