diff --git a/coderd/coderd.go b/coderd/coderd.go index 37e7d22a6d080..0aab4b26262ea 100644 --- a/coderd/coderd.go +++ b/coderd/coderd.go @@ -1532,17 +1532,19 @@ func New(options *Options) *API { // Add CSP headers to all static assets and pages. CSP headers only affect // browsers, so these don't make sense on api routes. - cspMW := httpmw.CSPHeaders(options.Telemetry.Enabled(), func() []string { - if api.DeploymentValues.Dangerous.AllowAllCors { - // In this mode, allow all external requests - return []string{"*"} - } - if f := api.WorkspaceProxyHostsFn.Load(); f != nil { - return (*f)() - } - // By default we do not add extra websocket connections to the CSP - return []string{} - }, additionalCSPHeaders) + cspMW := httpmw.CSPHeaders( + api.Experiments, + options.Telemetry.Enabled(), func() []string { + if api.DeploymentValues.Dangerous.AllowAllCors { + // In this mode, allow all external requests + return []string{"*"} + } + if f := api.WorkspaceProxyHostsFn.Load(); f != nil { + return (*f)() + } + // By default we do not add extra websocket connections to the CSP + return []string{} + }, additionalCSPHeaders) // Static file handler must be wrapped with HSTS handler if the // StrictTransportSecurityAge is set. We only need to set this header on diff --git a/coderd/httpmw/csp.go b/coderd/httpmw/csp.go index e6864b7448c41..afc19ddaf0c1f 100644 --- a/coderd/httpmw/csp.go +++ b/coderd/httpmw/csp.go @@ -4,6 +4,8 @@ import ( "fmt" "net/http" "strings" + + "github.com/coder/coder/v2/codersdk" ) // cspDirectives is a map of all csp fetch directives to their values. @@ -37,6 +39,7 @@ const ( CSPDirectiveFormAction CSPFetchDirective = "form-action" CSPDirectiveMediaSrc CSPFetchDirective = "media-src" CSPFrameAncestors CSPFetchDirective = "frame-ancestors" + CSPFrameSource CSPFetchDirective = "frame-src" CSPDirectiveWorkerSrc CSPFetchDirective = "worker-src" ) @@ -55,7 +58,7 @@ const ( // Example: https://github.com/coder/coder/issues/15118 // //nolint:revive -func CSPHeaders(telemetry bool, websocketHosts func() []string, staticAdditions map[CSPFetchDirective][]string) func(next http.Handler) http.Handler { +func CSPHeaders(experiments codersdk.Experiments, telemetry bool, websocketHosts func() []string, staticAdditions map[CSPFetchDirective][]string) func(next http.Handler) http.Handler { return func(next http.Handler) http.Handler { return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { // Content-Security-Policy disables loading certain content types and can prevent XSS injections. @@ -88,13 +91,21 @@ func CSPHeaders(telemetry bool, websocketHosts func() []string, staticAdditions CSPDirectiveMediaSrc: {"'self'"}, // Report all violations back to the server to log CSPDirectiveReportURI: {"/api/v2/csp/reports"}, - CSPFrameAncestors: {"'none'"}, // Only scripts can manipulate the dom. This prevents someone from // naming themselves something like ''. // "require-trusted-types-for" : []string{"'script'"}, } + if experiments.Enabled(codersdk.ExperimentAITasks) { + // AI tasks use iframe embeds of local apps. + // TODO: Handle region domains too, not just path based apps + cspSrcs.Append(CSPFrameAncestors, `'self'`) + cspSrcs.Append(CSPFrameSource, `'self'`) + } else { + cspSrcs.Append(CSPFrameAncestors, `'none'`) + } + if telemetry { // If telemetry is enabled, we report to coder.com. cspSrcs.Append(CSPDirectiveConnectSrc, "https://coder.com") diff --git a/coderd/httpmw/csp_test.go b/coderd/httpmw/csp_test.go index c5000d3a29370..bef6ab196eb6e 100644 --- a/coderd/httpmw/csp_test.go +++ b/coderd/httpmw/csp_test.go @@ -9,6 +9,7 @@ import ( "github.com/stretchr/testify/require" "github.com/coder/coder/v2/coderd/httpmw" + "github.com/coder/coder/v2/codersdk" ) func TestCSPConnect(t *testing.T) { @@ -20,7 +21,7 @@ func TestCSPConnect(t *testing.T) { r := httptest.NewRequest(http.MethodGet, "/", nil) rw := httptest.NewRecorder() - httpmw.CSPHeaders(false, func() []string { + httpmw.CSPHeaders(codersdk.Experiments{}, false, func() []string { return expected }, map[httpmw.CSPFetchDirective][]string{ httpmw.CSPDirectiveMediaSrc: expectedMedia,
Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.
Alternative Proxies: