Artifact a7a2fe8f8ff86d3024e11762323a42a1adf04ffa5026d8b6bb51ef38adccbd65:
- File
docs/RELEASE-NOTES-0.3.30.md
— part of check-in
[b637cbd37c]
at
2026-09-24 16:44:56
on branch trunk
— transport: refuse Basic over plain http to another host; drop it on a cross-host redirect
A Basic challenge was answered whatever the scheme, so over http the password crossed readable and the saved remote repeated it. It is now refused to non-loopback hosts, naming the https URL; a redirect to another host drops the credential; plain http to another host notes it on stderr. Release 0.3.30. (user: dmestas, size: 2933) [annotate] [blame] [check-ins using]
# zit 0.3.30 zit 0.3.30 stops sending passwords over plain `http://` to other hosts, and stops a redirect from handing a password to a different host. No artifact, tag namespace, sync message, or on-disk repository format changed. ## A Basic challenge over plain http to another host is refused When a server gates reads with HTTP Basic, zit answers the challenge with the password it was given — and did so whatever the URL's scheme. Basic is the password base64'd, so over `http://` it crossed the network readable by anyone on the path, and because the URL is saved as the checkout's remote, every later pull and push repeated it. Now, over `http://` to a host that isn't this machine, zit refuses to answer: ``` zit clone: refusing to send credentials over unencrypted http://host/r; use https://host/r ``` The check happens when the challenge arrives, not when a credential is given. A public repository cloned over http with `--user` is never challenged and still works. Loopback — `localhost`, `127.0.0.0/8`, `::1` — is allowed, since plaintext there never leaves the machine; that's how a forge talks to its own zit child and how the tests run. A name that only looks like loopback, such as `127.evil.example`, is not. ## A redirect to another host drops the password Once a challenge was answered, every later request in the exchange carried the credential, and a followed redirect rewrote the target to wherever `Location` pointed. So a server answering `302` could send the password on to a different host. A redirect that changes host now drops the credential for the rest of the exchange, which is what curl and browsers do. A redirect within the same host keeps it. An https-to-http redirect was already refused, credential or not, and still is. ## Plain http to another host says so The login card is safer than Basic, since it's signed over the payload and can't be replayed elsewhere. But over `http://` the payload itself still crosses readable, so a private repository's content is exposed either way. `clone`, `pull`, `push`, `sync` and `config pull` now print one note to stderr when the URL is plain http to another host: ``` zit clone: note: http://host/r is unencrypted http; what this exchange carries is readable in transit ``` Loopback prints nothing. There is no `--insecure-http` override. Nothing needs one today, and it's easy to add if something does. ## Compatibility - No on-disk repository or wire format changed; Fossil RFC revision 00 remains the target. - A clone, pull or push over `http://` to a non-loopback host that is challenged for HTTP Basic now fails with the message above instead of sending the password. Use the `https://` URL. - Syncing over `http://` to a non-loopback host adds one line to stderr. ## Qualification `zig fmt --check`, `zig build test`, `e2e`, `smoke`, `git-import-e2e`, `git-export-e2e`, and `dst`, plus the three-runner CI battery.