fix(security): make upstream TLS verification opt-in via settings flag

CodeQL alerts #70 and #71 (go/disabled-certificate-check) flagged the
hard-coded `InsecureSkipVerify: true` in handlers_proxy.go (the
/proxy/{url} reverse proxy) and mirror_middleware.go (the parity-check
mirror). Both target *.bose.com whose certificate chain is becoming
unreliable post end-of-service, but unconditionally disabling
verification is still wrong: a deployment that doesn't actually need
the bypass loses TLS hygiene for free.

Add an `AllowInsecureUpstreamTLS bool` field to datastore.Settings,
default false. Read it in both call sites — they aren't on a hot path
— and pass the value as InsecureSkipVerify. CodeQL accepts the
configurable boolean as a non-flag (vs. the previously hard-coded
`true`), and the runtime behaviour now defaults to verifying
certificates with an explicit opt-in for the broken-chain scenario.

Behaviour change: TLS upstream traffic is verified by default. Anyone
relying on the previous always-skip behaviour can re-enable it by
setting `"allow_insecure_upstream_tls": true` in settings.json.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
Tobias Gesellchen
2026-05-10 14:30:55 +02:00
co-authored by Claude Opus 4.7
parent be45b3485d
commit fbeae8bb11
3 changed files with 21 additions and 2 deletions
+6
View File
@@ -1800,6 +1800,12 @@ type Settings struct {
AmazonClientID string `json:"amazon_client_id,omitempty"`
AmazonClientSecret string `json:"amazon_client_secret,omitempty"`
AmazonRedirectURI string `json:"amazon_redirect_uri,omitempty"`
// AllowInsecureUpstreamTLS, when true, disables TLS certificate verification
// for the upstream Bose-cloud proxy and mirror traffic. The default (false)
// keeps verification on; opt in only when the upstream certificate chain is
// broken (post end-of-service) and a temporary unblock is required.
AllowInsecureUpstreamTLS bool `json:"allow_insecure_upstream_tls,omitempty"`
}
// GetSettings retrieves the global service settings.
+8 -1
View File
@@ -62,6 +62,13 @@ func (s *Server) ServeProxy(target *url.URL) http.HandlerFunc {
r.Body = io.NopCloser(bytes.NewBuffer(reqBody))
}
// AllowInsecureUpstreamTLS is opt-in via settings.json — defaults to
// false so the upstream certificate chain is verified normally. The
// opt-in exists for deployments stuck behind a broken Bose-cloud
// chain post end-of-service.
settings, _ := s.ds.GetSettings()
insecure := settings.AllowInsecureUpstreamTLS
rp := &httputil.ReverseProxy{
Rewrite: func(pr *httputil.ProxyRequest) {
pr.SetURL(target)
@@ -77,7 +84,7 @@ func (s *Server) ServeProxy(target *url.URL) http.HandlerFunc {
lp.LogRequest(pr.Out)
},
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
TLSClientConfig: &tls.Config{InsecureSkipVerify: insecure},
},
}
+7 -1
View File
@@ -271,6 +271,12 @@ func (s *Server) performMirror(r *http.Request) *mirrorResponseRecorder {
return nil
}
// AllowInsecureUpstreamTLS is opt-in via settings.json — defaults to
// false so verification stays on. The opt-in exists for deployments
// stuck behind a broken Bose-cloud certificate chain post EOS.
settings, _ := s.ds.GetSettings()
insecure := settings.AllowInsecureUpstreamTLS
// Create a proxy that doesn't write to the original ResponseWriter
proxy := &httputil.ReverseProxy{
Rewrite: func(pr *httputil.ProxyRequest) {
@@ -279,7 +285,7 @@ func (s *Server) performMirror(r *http.Request) *mirrorResponseRecorder {
pr.Out.Header.Set("X-Mirror-Request", "true")
},
Transport: &http.Transport{
TLSClientConfig: &tls.Config{InsecureSkipVerify: true},
TLSClientConfig: &tls.Config{InsecureSkipVerify: insecure},
},
}