uDDNS treats outbound HTTPS and local control planes as untrusted surfaces.
This page summarizes the built-in safeguards. .env.example remains the
complete environment-variable reference.
Provider API calls, public-IP echo requests, and notification webhooks dial HTTPS with pin-on-connect:
- Resolve the hostname.
- Reject loopback, link-local, cloud-metadata, and (by default) private addresses — including IPv4-mapped IPv6 and nip.io / sslip.io style embeds.
- Connect only to the verified address set (no second DNS lookup between check and TCP), which closes classic DNS-rebinding races.
Redirects never leave HTTPS and never change host when credentials or trusted echo answers are involved.
| Channel | Private LAN hosts | Loopback / metadata |
|---|---|---|
| Webhook / ntfy | Allowed | Always blocked |
| Slack / Discord | Blocked | Always blocked |
All notification URLs must be https:// without embedded userinfo.
DYNDNS_UPDATE_URL must be HTTPS and its hostname must appear on an allowlist.
Built-in hosts:
members.dyndns.orgmembers.dyndns.comupdate.dyndns.orgdynupdate.no-ip.comdynupdate.no-ip.org
Extend with DYNDNS_UPDATE_URL_ALLOW_HOSTS (comma-separated).
HTTPS echo endpoints are preferred because TLS authenticates the answer.
Optional DNS fallbacks (UDDNS_IP_DNS_FALLBACK=true) are off by default —
plain DNS can be forged on-path. Custom UDDNS_IP_HTTPS_V4 /
UDDNS_IP_HTTPS_V6 endpoints must be HTTPS and are resolved under the same
host-safety rules before connect.
When UDDNS_HEALTH=1:
- Loopback still requires
UDDNS_HEALTH_AUTH_TOKENunlessUDDNS_HEALTH_ALLOW_INSECURE_LOOPBACK=true. - Non-loopback requires the auth token plus TLS cert/key.
- With auth configured,
/metricsand/eventsrequire the bearer token;/healthzand/readyzstay open for probes.
Same pattern: loopback requires UDDNS_MCP_AUTH_TOKEN unless
UDDNS_MCP_ALLOW_INSECURE_LOOPBACK=true. Non-loopback requires token + TLS.
Live destructive MCP tools (check_once, force_update, update_hosts,
start_loop) also require confirm: true.
- Absolute
UDDNS_STATE_FILE/UDDNS_HISTORY_FILEpaths must stay underUDDNS_DATA_DIRwhen that root is set (path jail). - Check intervals are clamped to
60000–86400000ms (60 s–24 h) forUDDNS_INTERVALand MCPset_interval.
Tokens, passwords, Authorization headers, usernames, and OAuth client IDs
are redacted from log context and history messages. Prefer provider-specific
env vars over putting secrets in URLs.
Supply-chain inputs are immutable in CI and release builds:
- Third-party GitHub Actions use full 40-character commit SHAs.
- Docker base images and container actions use SHA-256 digests.
- pnpm dependency resolutions carry SHA-256 or SHA-512 integrity values, and
workflow installs use
--frozen-lockfile.
Run pnpm run deps:check locally to validate the policy. The supply-chain
CI job runs on every pull request and push to main, independent of path
filters, and is a required branch-protection check.