From 303fc0c8dcd2e8b7035c954f3f86c3844455fdab Mon Sep 17 00:00:00 2001 From: reverse Date: Wed, 19 Aug 2026 01:32:17 +0000 Subject: [PATCH] =?UTF-8?q?filehost:=20use=20only=20the=20final=20path=20s?= =?UTF-8?q?egment=20of=20the=20URL=20as=20the=20displayed=20filename=20tag?= =?UTF-8?q?=20=E2=80=94=20the=20trailing=20part=20was=20taken=20verbatim?= =?UTF-8?q?=20(path=20separators,=20../),=20and=20while=20json=5Fesc/escap?= =?UTF-8?q?e=5Ftag=20block=20injection,=20a=20client=20rendering=20filenam?= =?UTF-8?q?e=20could=20be=20misled=20by=20traversal;=20take=20the=20basena?= =?UTF-8?q?me?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/modules/filehost.rs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/modules/filehost.rs b/src/modules/filehost.rs index e24d556..72968bf 100644 --- a/src/modules/filehost.rs +++ b/src/modules/filehost.rs @@ -129,7 +129,10 @@ impl Module for FileHost { let rest = &text[pos..]; let end = rest.find(|c: char| c.is_whitespace()).unwrap_or(rest.len()); let url = rest[..end].trim_end_matches([',', '.', ';', ':', '!', '?', ')', ']', '}']); - let filename = &url[files_prefix.len().min(url.len())..]; + let raw_name = &url[files_prefix.len().min(url.len())..]; + // display only the final path segment, so a `../` or nested path in the URL + // can't mislead a client that renders the filename tag + let filename = raw_name.rsplit(['/', '\\']).next().unwrap_or(raw_name); let meta = format!( "{{\"url\":\"{}\",\"filename\":\"{}\",\"type\":\"{}\"}}", json_esc(url),