From e29a0dc5dfed4bb62b894e059c9506873d32a62c Mon Sep 17 00:00:00 2001 From: Alexander Petric Date: Tue, 13 Oct 2026 11:52:25 -0400 Subject: [PATCH] fix: serve s3 proxy objects with nosniff and a sandbox csp (#11731) * fix: serve s3 proxy objects with nosniff and a sandbox csp Co-Authored-By: Claude Opus 5.5 (1M context) * test: assert s3 proxy error responses carry nosniff and the sandbox csp Co-Authored-By: Claude Opus 5.5 (1M context) * chore: update ee-repo-ref to 196abc042c691ea16280ee10b89fb3b2fd527236 This commit updates the EE repository reference after PR #876 was merged in windmill-ee-private. Previous ee-repo-ref: 25feaf41aa84d47f8e4adb4def2576b443a66374 New ee-repo-ref: 196abc042c691ea16280ee10b89fb3b2fd527236 Automated by sync-ee-ref workflow. --------- Co-authored-by: Claude Opus 5.5 (1M context) Co-authored-by: windmill-internal-app[bot] --- backend/ee-repo-ref.txt | 2 +- backend/tests/s3_proxy_headers.rs | 29 +++++++++++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) create mode 100644 backend/tests/s3_proxy_headers.rs diff --git a/backend/ee-repo-ref.txt b/backend/ee-repo-ref.txt index 408bf517b1..bbd2895dd5 100644 --- a/backend/ee-repo-ref.txt +++ b/backend/ee-repo-ref.txt @@ -1 +1 @@ -118785eaa78675089b9a676d24e5d0a2e03f3d9a +196abc042c691ea16280ee10b89fb3b2fd527236 diff --git a/backend/tests/s3_proxy_headers.rs b/backend/tests/s3_proxy_headers.rs new file mode 100644 index 0000000000..8f43f8c761 --- /dev/null +++ b/backend/tests/s3_proxy_headers.rs @@ -0,0 +1,29 @@ +//! Every s3_proxy response carries `nosniff` and the sandbox CSP, error responses included, +//! since the presigned route serves workspace objects from the app origin without a login. +#![cfg(all(feature = "enterprise", feature = "private", feature = "parquet"))] + +use sqlx::{Pool, Postgres}; +use windmill_test_utils::*; + +#[sqlx::test(fixtures("base"))] +async fn test_s3_proxy_sets_content_security_headers(db: Pool) -> anyhow::Result<()> { + initialize_tracing().await; + + let server = ApiServer::start(db.clone()).await?; + let port = server.addr.port(); + + let resp = reqwest::Client::new() + .get(format!( + "http://localhost:{port}/api/w/test-workspace/s3_proxy/_default_/x.html?exp=9999999999&sig=00" + )) + .send() + .await?; + + assert!(resp.status().is_client_error(), "status: {}", resp.status()); + assert_eq!(resp.headers()["x-content-type-options"], "nosniff"); + assert_eq!( + resp.headers()["content-security-policy"], + "sandbox allow-scripts allow-forms allow-popups allow-modals allow-downloads" + ); + Ok(()) +}