Escape paths in SBPL profile to prevent sandbox injection

Richard Feldman created

Paths interpolated into the macOS Seatbelt SBPL profile were not
escaped, allowing a crafted path containing double-quote characters
to inject arbitrary SBPL rules and potentially disable the sandbox.

Add sbpl_escape() which escapes backslash and double-quote characters
in path strings before interpolation into SBPL literal and subpath
forms.

Change summary

crates/terminal/src/sandbox_macos.rs | 15 +++++++++++++--
1 file changed, 13 insertions(+), 2 deletions(-)

Detailed changes

crates/terminal/src/sandbox_macos.rs 🔗

@@ -108,7 +108,11 @@ fn generate_sbpl_profile(config: &SandboxConfig) -> String {
         ] {
             let path = home.join(dotfile);
             if path.exists() {
-                let _ = write!(p, "(allow file-read* (literal \"{}\"))\n", path.display());
+                let _ = write!(
+                    p,
+                    "(allow file-read* (literal \"{}\"))\n",
+                    sbpl_escape(&path)
+                );
             }
         }
         // XDG config directory
@@ -128,10 +132,17 @@ fn generate_sbpl_profile(config: &SandboxConfig) -> String {
     p
 }
 
+fn sbpl_escape(path: &Path) -> String {
+    path.display()
+        .to_string()
+        .replace('\\', "\\\\")
+        .replace('"', "\\\"")
+}
+
 fn write_subpath_rule(p: &mut String, path: &Path, permissions: &str) {
     let _ = write!(
         p,
         "(allow {permissions} (subpath \"{}\"))\n",
-        path.display()
+        sbpl_escape(path)
     );
 }