From fb0757846cac54cead0fdd0e16794c2833cfd90b Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Wed, 14 Oct 2026 06:12:47 +0000 Subject: [PATCH] =?UTF-8?q?=F0=9F=9B=A1=EF=B8=8F=20Sentinel:=20[MEDIUM]=20?= =?UTF-8?q?Add=20HTTP=20security=20headers=20middleware?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 🚨 Severity: MEDIUM 💡 Vulnerability: The Axum backend lacked essential HTTP security headers (Strict-Transport-Security, X-Frame-Options, X-Content-Type-Options) exposing the application to clickjacking and MIME-sniffing risks. 🎯 Impact: Attackers could potentially embed the app in iframes or execute content misinterpretations. 🔧 Fix: Implemented an Axum middleware layer (`security_headers`) to automatically set `DENY`, `nosniff`, and HSTS defaults globally across endpoints. ✅ Verification: Review `apps/server/src/security.rs` and the router layer integration in `apps/server/src/main.rs`. All tests pass. Co-authored-by: bobdivx <6737167+bobdivx@users.noreply.github.com> --- .jules/sentinel.md | 4 ++++ apps/server/src/main.rs | 2 ++ apps/server/src/security.rs | 22 ++++++++++++++++++++++ 3 files changed, 28 insertions(+) diff --git a/.jules/sentinel.md b/.jules/sentinel.md index ffc0bd2ced..7782954295 100644 --- a/.jules/sentinel.md +++ b/.jules/sentinel.md @@ -2,3 +2,7 @@ **Vulnerability:** The manual SVG sanitizer `apps/web/src/lib/sanitize-svg.ts` used an insufficient allowlist/blocklist. It allowed ``, ``, ``, ``, ``, and `` which could lead to mutation XSS (mXSS) and other attack vectors when rendering untrusted Mermaid or Math blocks. **Learning:** Manual DOM tree sanitization is notoriously hard to get right because attackers can hide active elements (e.g. `` tags with `javascript:` payloads) inside grandchild trees (like ``) or use SVG-specific tricks (like ``) which naive list-based cleaners overlook. **Prevention:** Rather than adding heavy third-party dependencies (like DOMPurify) against explicit project instructions, expanding the `BLOCKED` Set to include these structural injection vectors provides a robust, zero-dependency mitigation. Future expansions should verify nested elements carefully. +## 2026-10-14 - [Axum Middleware Security Headers] +**Vulnerability:** Missing fundamental security headers (X-Frame-Options, X-Content-Type-Options, Strict-Transport-Security) across the Axum HTTP routing backend (`apps/server/src/security.rs`). +**Learning:** Axum provides easy layer definitions using `middleware::from_fn`. We can inject these security headers universally into existing router layers without disrupting other caching (`static_cache_headers`) or CORS (`cors_layer`) mechanisms. +**Prevention:** When developing custom backend routing in Rust Axum, ensure a standard middleware layer enforces security headers alongside CORS configurations to provide defense in depth against client-side exploitation such as clickjacking and MIME-sniffing. diff --git a/apps/server/src/main.rs b/apps/server/src/main.rs index 71dfc8e3d0..3c5b653340 100644 --- a/apps/server/src/main.rs +++ b/apps/server/src/main.rs @@ -195,6 +195,7 @@ async fn main() -> Result<(), Box> { }); } let mut app = worker::worker_router(state.clone()) + .layer(middleware::from_fn(security::security_headers)) .layer(middleware::from_fn(security::static_cache_headers)) .layer(security::cors_layer()) .layer(TraceLayer::new_for_http()); @@ -392,6 +393,7 @@ async fn main() -> Result<(), Box> { state.clone(), worker::fence_stale_leader, )) + .layer(middleware::from_fn(security::security_headers)) .layer(middleware::from_fn(security::static_cache_headers)) .layer(security::cors_layer()) .layer(TraceLayer::new_for_http()) diff --git a/apps/server/src/security.rs b/apps/server/src/security.rs index 8ea417ea1c..85f655849d 100644 --- a/apps/server/src/security.rs +++ b/apps/server/src/security.rs @@ -49,6 +49,28 @@ pub fn cors_layer() -> CorsLayer { ]) } +/// Ajoute les headers de sécurité HTTP (X-Frame-Options, X-Content-Type-Options, HSTS). +pub async fn security_headers(req: Request, next: Next) -> Response { + let mut res = next.run(req).await; + + // HSTS : Strict-Transport-Security, max-age=1 year, includeSubDomains + res.headers_mut().insert( + header::STRICT_TRANSPORT_SECURITY, + HeaderValue::from_static("max-age=31536000; includeSubDomains") + ); + // Anti-Clickjacking : X-Frame-Options DENY + res.headers_mut().insert( + header::X_FRAME_OPTIONS, + HeaderValue::from_static("DENY") + ); + // Anti-MIME-Sniffing : X-Content-Type-Options nosniff + res.headers_mut().insert( + header::X_CONTENT_TYPE_OPTIONS, + HeaderValue::from_static("nosniff") + ); + res +} + /// HTML / routes app : pas de cache (évite page blanche après MAJ Flatpak). /// Assets fingerprinted `/_astro/*` : cache long. pub async fn static_cache_headers(req: Request, next: Next) -> Response {