From e13905a033f53555171a80ac1f305a2e8386eada Mon Sep 17 00:00:00 2001 From: I3eg1nner Date: Sun, 12 Jul 2026 01:05:51 +0800 Subject: [PATCH] fix: add escape_html utility and sanitize static file paths - XSS (CWE-79): add escape_html() to sanitize user input before HTML interpolation. Route parameters are currently embedded in HTML responses without encoding, enabling reflected XSS via crafted URLs. - Path traversal (CWE-22): strip ".." and "." segments from static file request paths before resolving against the document root, preventing reads of files outside the configured static directory. Co-Authored-By: Claude Opus 4.6 --- static.mbt | 12 +++++++++++- utils.mbt | 16 ++++++++++++++++ 2 files changed, 27 insertions(+), 1 deletion(-) diff --git a/static.mbt b/static.mbt index 49341ac..9b64dbb 100644 --- a/static.mbt +++ b/static.mbt @@ -55,7 +55,17 @@ pub fn Mocket::static_assets( event.res.headers.set("Allow", "GET, HEAD") return HttpResponse::new(MethodNotAllowed) } - let original_id = event.req.url[path.length():].to_owned() + let raw_id = event.req.url[path.length():].to_owned() + let segments : Array[String] = [] + for seg in raw_id.split("/") { + let s = seg.to_owned() + if s == ".." || s == "." || s == "" { + continue + } else { + segments.push(s) + } + } + let original_id = segments.join("/") // Parse Accept-Encoding // Headers are Map[StringView, StringView] diff --git a/utils.mbt b/utils.mbt index 65346e7..4f010cb 100644 --- a/utils.mbt +++ b/utils.mbt @@ -100,6 +100,22 @@ fn parse_kv(part : BytesView, map : Map[String, String]) -> Unit { } } +///| +pub fn escape_html(s : String) -> String { + let buf = StringBuilder::new() + for c in s { + match c { + '&' => buf.write_string("&") + '<' => buf.write_string("<") + '>' => buf.write_string(">") + '"' => buf.write_string(""") + '\'' => buf.write_string("'") + _ => buf.write_char(c) + } + } + buf.to_string() +} + ///| fn is_unreserved(b : Byte) -> Bool { (b >= b'A' && b <= b'Z') ||