From 8c4907a6260ab3e3330f8d32b61b30474396cd2f Mon Sep 17 00:00:00 2001 From: oracola91 <118899664+oracola91@users.noreply.github.com> Date: Fri, 23 Oct 2026 13:53:24 +0300 Subject: [PATCH] PDF export also drops smb: links An smb://host/share link is a path to another machine too: opening it connects to that host (macOS and Linux file managers open these links). It is now left out of the PDF like the other network-share links, and the test covers it. --- crates/pdf/src/lib.rs | 8 ++++---- crates/pdf/src/tests.rs | 1 + 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/crates/pdf/src/lib.rs b/crates/pdf/src/lib.rs index 6d3f5f42..5683b675 100644 --- a/crates/pdf/src/lib.rs +++ b/crates/pdf/src/lib.rs @@ -695,9 +695,9 @@ fn to_path(bp: &kurbo::BezPath) -> Option { /// Can a hyperlink from a (possibly untrusted) deck become a PDF link? Scripts (`javascript:`, /// `vbscript:`), `data:` and paths to another machine (`\\host\share`, `//host/share`, -/// `file://host/...`) cannot: on Windows, opening a network path sends the user's NTLM credentials -/// to that host. Web, mail, local `file:` and relative links can. Read the way a browser reads a -/// URL: control characters dropped, leading spaces trimmed, any case. +/// `file://host/...`, `smb://host/...`) cannot: opening one connects to that host, which on Windows +/// sends the user's NTLM credentials. Web, mail, local `file:` and relative links can. Read the way +/// a browser reads a URL: control characters dropped, leading spaces trimmed, any case. fn exportable_url(url: &str) -> bool { let u: String = url.chars().filter(|c| !c.is_ascii_control()).collect(); let u = u.trim_start().replace('\\', "/"); @@ -706,7 +706,7 @@ fn exportable_url(url: &str) -> bool { } let Some((scheme, rest)) = u.split_once(':') else { return true }; match scheme.to_ascii_lowercase().as_str() { - "javascript" | "vbscript" | "data" => false, + "javascript" | "vbscript" | "data" | "smb" => false, "file" => match rest.strip_prefix("//") { // `file:///C:/...` and `file://localhost/...` are local; `file://host/...` and `file:////host/...` are not. Some(p) => { diff --git a/crates/pdf/src/tests.rs b/crates/pdf/src/tests.rs index ff349b4b..74e2daf0 100644 --- a/crates/pdf/src/tests.rs +++ b/crates/pdf/src/tests.rs @@ -149,6 +149,7 @@ fn unsafe_url_links_are_not_exported() { "//attacker.example/share/x", "file://attacker.example/share/x", "file:////attacker.example/share/x", + "smb://attacker.example/share/x", ]; let mut p = deck(1); let slide = Arc::make_mut(&mut p.slides[0]);