Commit 928b919242

928b9192421c88e67439ef307a9ce9729f89f37d

parent: 6f553fea02

Verified · cmc ci/build: success ci/test: success

cmc <hello@cleberg.net> · 2026-09-28 08:25 UTC

https: TLS 1.2 minimum, set explicitly

Closes #281

Layout: unified · split

.gitbay/wiki/Admin.org +4
@@ -78,6 +78,10 @@ validation still prints, followed by the contradiction.
7878 site_url with a public DNS name.
7979- =files=: =cert_file= + =key_file=.
8080- =off=: plain HTTP — development, or behind a TLS-terminating proxy.
81- The HTTPS listener accepts TLS 1.2 and 1.3 only (=serverTLS= in
82 =cmd/gitbayd/tls.go=), with the default cipher suites of the Go
83 release the binary was built with. =openssl s_client -connect
84 <host>:443 -tls1_1= fails the handshake.
8185
8286=trusted_proxies= lists the addresses or CIDRs of reverse proxies in
8387front of the daemon. A request from one of them is attributed, for API
.gitbay/wiki/Architecture/06-Data-and-Cryptography.org +3 −3
@@ -56,7 +56,7 @@ secret, webhook secret and mirror token.
5656| Channel | Protection |
5757|--------------------------+--------------------------------------------------------------|
5858| SSH | Go =x/crypto/ssh=; ed25519 host key generated on first start |
59| HTTPS | TLS via ACME or operator certificates; HSTS one year |
59| HTTPS | TLS 1.2 minimum (=cmd/gitbayd/tls.go=), ACME or operator certificates; HSTS one year |
6060| HTTP port 80 | ACME challenges and redirect only |
6161| git:// | none (public data only; off by default) |
6262| Runner ↔ server | SSH |
@@ -65,8 +65,8 @@ secret, webhook secret and mirror token.
6565| Webhooks | TLS when the URL is https; HMAC-SHA256 body signature in =X-Gitbay-Signature-256= (=internal/webhook/webhook.go=) |
6666| Mirrors | per URL; token passed through =GIT_ASKPASS=, never argv (=internal/mirror/mirror.go=) |
6767
68The TLS configuration uses Go's defaults; no minimum version or cipher
69list is set in code.
68TLS 1.2 is the minimum, set in code (=serverTLS= in
69=cmd/gitbayd/tls.go=); cipher suites are Go's defaults.
7070
7171* Cryptographic primitives
7272
.gitbay/wiki/Architecture/10-Known-Gaps.org −1
@@ -21,7 +21,6 @@ what the 2026-09-27 review found; remove a row when its issue closes.
2121| #275 | Audit | Refused writes are not audited; the audit table is writable by the daemon user | medium |
2222| #279 | SSRF | Mirror URLs are checked when saved, not when git connects | medium |
2323| #280 | Mail | STARTTLS only when the relay offers it | medium |
24| #281 | TLS | No explicit minimum TLS version | low |
2524| #282 | Hook socket | Anything that can open =hook.sock= can act as any user | medium |
2625| #297 | Credentials | A browser session can mint tokens and keys that outlive it | low |
2726
CHANGELOG.org +2
@@ -33,6 +33,8 @@ must add =--scope full=. Existing tokens keep their scope.
3333 hours. =web sessions list= shows when each was last used (#276).
3434- =web login= over SSH refuses a sixth link in an hour, the same bound
3535 the login page's mailed links have (#278).
36- The HTTPS listener refuses TLS below 1.2, in both certificate modes
37 (#281).
3638
3739* v1.36.0 — 2026-09-23
3840
cmd/gitbayd/main.go +2 −1
@@ -239,6 +239,7 @@ func serveCmd() *cobra.Command {
239239 case "off":
240240 errCh <- hs.ListenAndServe()
241241 case "files":
242 hs.TLSConfig = serverTLS(nil)
242243 errCh <- hs.ListenAndServeTLS(cfg.HTTP.CertFile, cfg.HTTP.KeyFile)
243244 case "acme":
244245 host := cfg.SiteHost()
@@ -298,7 +299,7 @@ func serveCmd() *cobra.Command {
298299 }
299300 }()
300301 }
301 hs.TLSConfig = m.TLSConfig()
302 hs.TLSConfig = serverTLS(m.TLSConfig())
302303 errCh <- hs.ListenAndServeTLS("", "")
303304 }
304305 }()
cmd/gitbayd/tls.go added +13
@@ -0,0 +1,13 @@
1package main
2
3import "crypto/tls"
4
5// serverTLS sets the HTTPS listener's protocol floor: TLS 1.2 and 1.3,
6// with Go's default cipher suites.
7func serverTLS(c *tls.Config) *tls.Config {
8 if c == nil {
9 c = &tls.Config{}
10 }
11 c.MinVersion = tls.VersionTLS12
12 return c
13}
cmd/gitbayd/tls_test.go added +21
@@ -0,0 +1,21 @@
1package main
2
3import (
4 "crypto/tls"
5 "testing"
6)
7
8// The floor is stated in code rather than inherited from the Go
9// release the binary was built with (#281).
10func TestServerTLSMinimum(t *testing.T) {
11 if got := serverTLS(nil).MinVersion; got != tls.VersionTLS12 {
12 t.Fatalf("files mode: MinVersion %#x, want %#x", got, tls.VersionTLS12)
13 }
14 // autocert's config carries the ALPN protocols TLS-ALPN-01 needs;
15 // setting the floor must keep them.
16 base := &tls.Config{NextProtos: []string{"h2", "http/1.1", "acme-tls/1"}}
17 got := serverTLS(base)
18 if got.MinVersion != tls.VersionTLS12 || len(got.NextProtos) != 3 {
19 t.Fatalf("acme mode: %+v", got)
20 }
21}