From 2f75ab1053b4aa79c00f0f77fe1c099f9a118308 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Sat, 24 Oct 2026 05:51:30 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM]=20?= =?UTF-8?q?Add=20security=20headers=20to=20backend=20responses?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Adds `X-Frame-Options: DENY`, `X-Content-Type-Options: nosniff`, and `Strict-Transport-Security` headers to all responses handled by `static_cache_headers` middleware in `apps/server/src/security.rs`. - Uses `axum::http::header` constants for safety and conciseness. - Appends Axum headers learning to `.jules/sentinel.md`. Co-authored-by: bobdivx <6737167+bobdivx@users.noreply.github.com> --- .jules/sentinel.md | 5 +++++ apps/server/src/security.rs | 13 +++++++++++++ 2 files changed, 18 insertions(+) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index 1a95282559..674011f8fa 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -17,3 +17,8 @@ **Vulnerability:** The `verify_github_sig` function in `apps/server/src/infra_routes.rs` verified GitHub webhook signatures using standard string comparison `expected.eq_ignore_ascii_case(hex_sig)`. **Learning:** String comparison functions exit early as soon as a character mismatch is found. In a cryptographic context, this variable response time leaks information and allows an attacker to perform a timing attack to forge a valid HMAC signature by guessing it byte by byte. **Prevention:** Always use a constant-time comparison library (like `hmac`'s `verify_slice()`) to compare cryptographic hashes, secrets, and signatures to prevent side-channel timing attacks. Avoid custom implementations of standard cryptographic algorithms. + +## 2023-10-24 - [Add Security Headers to Backend] +**Vulnerability:** Missing critical security headers (X-Frame-Options, X-Content-Type-Options, Strict-Transport-Security) in Axum HTTP responses. +**Learning:** In axum, the `HeaderName::from_static` method strictly requires the header string to be lowercase (e.g., `x-frame-options`). Using uppercase letters will cause a runtime panic. The `security.rs` file manages static asset and cache headers via middleware where these security headers should logically reside. +**Prevention:** Always verify that all newly added HTTP headers in the axum backend use exclusively lowercase strings when passing to `from_static` or `insert`. Consider creating a unified security middleware in `security.rs` that applies strict defaults (like `nosniff` and HSTS) to all endpoints to enforce defense in depth. diff --git a/apps/server/src/security.rs b/apps/server/src/security.rs index 8ea417ea1c..82dbeaff03 100644 --- a/apps/server/src/security.rs +++ b/apps/server/src/security.rs @@ -54,6 +54,18 @@ pub fn cors_layer() -> CorsLayer { pub async fn static_cache_headers(req: Request
, next: Next) -> Response { let path = req.uri().path().to_string(); let mut res = next.run(req).await; + + // Ajout des en-têtes de sécurité de base pour toutes les requêtes interceptées + if let Ok(v) = HeaderValue::from_str("DENY") { + res.headers_mut().insert(header::X_FRAME_OPTIONS, v); + } + if let Ok(v) = HeaderValue::from_str("nosniff") { + res.headers_mut().insert(header::X_CONTENT_TYPE_OPTIONS, v); + } + if let Ok(v) = HeaderValue::from_str("max-age=31536000; includeSubDomains") { + res.headers_mut().insert(header::STRICT_TRANSPORT_SECURITY, v); + } + let value = if path.starts_with("/_astro/") { "public, max-age=31536000, immutable" } else if path.ends_with(".html") @@ -67,5 +79,6 @@ pub async fn static_cache_headers(req: Request, next: Next) -> Response