fix(core): reject cleartext Plain TLS to non-loopback hosts #335

Merged
KofTwentyTwo merged 2 commits from story/ws-d1-reject-plain-remote into dev 2026-07-31 18:35:15 +00:00
KofTwentyTwo commented 2026-07-31 18:28:17 +00:00 (Migrated from github.com)

Summary

  • AccountConfig::validate now rejects TlsMode::Plain for imap_tls_mode/smtp_tls_mode when the corresponding host is not loopback, preventing a misconfiguration from sending credentials in cleartext over the network.
  • Scope extended per an automated security-review finding: the CalDAV collection_url validation had the same gap — it only checked the URL scheme prefix, so http://<remote-host>/... was accepted and would send Basic-auth credentials in cleartext to a remote host. The same loopback-only-cleartext rule now applies: plain http:// is accepted only when the URL's host is loopback; any other host must use https://. Non-http(s) schemes still fail with InvalidCollectionUrl as before.
  • Both checks share one is_loopback_host helper and the same ConfigError::CleartextToRemoteHost { endpoint, host } error variant (endpoint tagged "imap", "smtp", or "caldav").
  • Plain/http:// remain allowed for local test servers (127.0.0.1, ::1, localhost, case-insensitive).
  • ImplicitTls/StartTls behavior is unchanged.
  • Updated the accounts_lifecycle_e2e_test fixture's SMTP host from a remote-looking hostname to 127.0.0.1 since it exercises TlsMode::Plain on SMTP.

Test plan

  • Mail-side unit tests: plain_imap_to_remote_host_fails_validation, plain_smtp_to_remote_host_fails_validation, plain_imap_and_smtp_to_loopback_hosts_pass_validation (127.0.0.1/localhost/::1/LOCALHOST), implicit_tls_and_starttls_to_remote_host_pass_validation.
  • CalDAV-side unit tests: caldav_account_rejects_cleartext_http_to_remote_host, caldav_account_accepts_https_to_remote_host, caldav_account_accepts_cleartext_http_to_loopback_host (127.0.0.1/localhost).
  • Existing account-validation and CalDAV-account tests (#254) still green, unmodified.
  • cargo fmt --all -- --check
  • cargo check-all (clippy --all-targets -D warnings)
  • cargo test-all (0 failed, 0 ignored)

Refs #297

## Summary - `AccountConfig::validate` now rejects `TlsMode::Plain` for `imap_tls_mode`/`smtp_tls_mode` when the corresponding host is not loopback, preventing a misconfiguration from sending credentials in cleartext over the network. - Scope extended per an automated security-review finding: the CalDAV `collection_url` validation had the same gap — it only checked the URL scheme prefix, so `http://<remote-host>/...` was accepted and would send Basic-auth credentials in cleartext to a remote host. The same loopback-only-cleartext rule now applies: plain `http://` is accepted only when the URL's host is loopback; any other host must use `https://`. Non-`http(s)` schemes still fail with `InvalidCollectionUrl` as before. - Both checks share one `is_loopback_host` helper and the same `ConfigError::CleartextToRemoteHost { endpoint, host }` error variant (`endpoint` tagged `"imap"`, `"smtp"`, or `"caldav"`). - `Plain`/`http://` remain allowed for local test servers (`127.0.0.1`, `::1`, `localhost`, case-insensitive). - `ImplicitTls`/`StartTls` behavior is unchanged. - Updated the `accounts_lifecycle_e2e_test` fixture's SMTP host from a remote-looking hostname to `127.0.0.1` since it exercises `TlsMode::Plain` on SMTP. ## Test plan - [x] Mail-side unit tests: `plain_imap_to_remote_host_fails_validation`, `plain_smtp_to_remote_host_fails_validation`, `plain_imap_and_smtp_to_loopback_hosts_pass_validation` (127.0.0.1/localhost/::1/LOCALHOST), `implicit_tls_and_starttls_to_remote_host_pass_validation`. - [x] CalDAV-side unit tests: `caldav_account_rejects_cleartext_http_to_remote_host`, `caldav_account_accepts_https_to_remote_host`, `caldav_account_accepts_cleartext_http_to_loopback_host` (127.0.0.1/localhost). - [x] Existing account-validation and CalDAV-account tests (#254) still green, unmodified. - [x] `cargo fmt --all -- --check` - [x] `cargo check-all` (clippy --all-targets -D warnings) - [x] `cargo test-all` (0 failed, 0 ignored) Refs #297
Sign in to join this conversation.