Skip to content

Commit e225ee0

Browse files
🔒 Fix command injection vulnerability in std.notification by using notify-rust library
Co-authored-by: Tcode-Motion <188012755+Tcode-Motion@users.noreply.github.com>
1 parent dddc025 commit e225ee0

1 file changed

Lines changed: 59 additions & 34 deletions

File tree

‎stdlib/src/notification.rs‎

Lines changed: 59 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -30,30 +30,10 @@ impl StdlibRegistry {
3030
}
3131
let title = args[0].to_string();
3232
let body = args[1].to_string();
33-
#[cfg(target_os = "windows")]
34-
{
35-
use base64::Engine;
36-
use std::process::Command;
37-
38-
let b64_title = base64::engine::general_purpose::STANDARD.encode(title.encode_utf16().flat_map(|c| c.to_le_bytes()).collect::<Vec<u8>>());
39-
let b64_body = base64::engine::general_purpose::STANDARD.encode(body.encode_utf16().flat_map(|c| c.to_le_bytes()).collect::<Vec<u8>>());
40-
41-
let script = format!(
42-
"Add-Type -AssemblyName PresentationFramework; [System.Windows.MessageBox]::Show([System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('{}')), [System.Text.Encoding]::Unicode.GetString([System.Convert]::FromBase64String('{}')))",
43-
b64_body, b64_title
44-
);
45-
let b64_script = base64::engine::general_purpose::STANDARD.encode(script.encode_utf16().flat_map(|c| c.to_le_bytes()).collect::<Vec<u8>>());
46-
47-
let _ = Command::new("powershell")
48-
.args(["-EncodedCommand", &b64_script])
49-
.spawn();
50-
}
51-
#[cfg(not(target_os = "windows"))]
52-
{
53-
let _ = std::process::Command::new("notify-send")
54-
.args([&title, &body])
55-
.spawn();
56-
}
33+
let _ = notify_rust::Notification::new()
34+
.summary(&title)
35+
.body(&body)
36+
.show();
5737
Ok(RuntimeValue::Null)
5838
},
5939
}),
@@ -76,16 +56,10 @@ impl StdlibRegistry {
7656
));
7757
}
7858
let msg = args[0].to_string();
79-
#[cfg(target_os = "windows")]
80-
{
81-
let _ = std::process::Command::new("msg").args(["*", &msg]).spawn();
82-
}
83-
#[cfg(not(target_os = "windows"))]
84-
{
85-
let _ = std::process::Command::new("notify-send")
86-
.args(["Alert", &msg])
87-
.spawn();
88-
}
59+
let _ = notify_rust::Notification::new()
60+
.summary("Alert")
61+
.body(&msg)
62+
.show();
8963
Ok(RuntimeValue::Null)
9064
},
9165
}),
@@ -127,4 +101,55 @@ mod tests {
127101
assert_eq!(alert.name(), "alert");
128102
assert_eq!(alert.arity(), 1);
129103
}
104+
105+
#[test]
106+
fn test_notification_execution_capability_denied() {
107+
let mut registry = StdlibRegistry {
108+
modules: std::collections::HashMap::new(),
109+
};
110+
registry.register_notification();
111+
let module = registry.get_module("std.notification").unwrap();
112+
let show = module.exports.get("show").unwrap();
113+
let alert = module.exports.get("alert").unwrap();
114+
115+
let mut config = techscript_runtime::RuntimeConfig::default();
116+
config.capabilities.remove(&Capability::Process);
117+
let mut ctx = techscript_runtime::RuntimeContext::new(config);
118+
let args_show = vec![
119+
RuntimeValue::Str("Test Title".to_string()),
120+
RuntimeValue::Str("Test Body".to_string()),
121+
];
122+
let res_show = show.call(&mut ctx, args_show);
123+
assert!(res_show.is_err());
124+
125+
let args_alert = vec![RuntimeValue::Str("Test Message".to_string())];
126+
let res_alert = alert.call(&mut ctx, args_alert);
127+
assert!(res_alert.is_err());
128+
}
129+
130+
#[test]
131+
fn test_notification_execution_capability_granted() {
132+
let mut registry = StdlibRegistry {
133+
modules: std::collections::HashMap::new(),
134+
};
135+
registry.register_notification();
136+
let module = registry.get_module("std.notification").unwrap();
137+
let show = module.exports.get("show").unwrap();
138+
let alert = module.exports.get("alert").unwrap();
139+
140+
let mut config = techscript_runtime::RuntimeConfig::default();
141+
config.capabilities.insert(Capability::Process);
142+
let mut ctx = techscript_runtime::RuntimeContext::new(config);
143+
144+
let args_show = vec![
145+
RuntimeValue::Str("Title; calc.exe".to_string()),
146+
RuntimeValue::Str("Body; rm -rf /".to_string()),
147+
];
148+
let res_show = show.call(&mut ctx, args_show);
149+
assert!(res_show.is_ok());
150+
151+
let args_alert = vec![RuntimeValue::Str("Alert Message; id".to_string())];
152+
let res_alert = alert.call(&mut ctx, args_alert);
153+
assert!(res_alert.is_ok());
154+
}
130155
}

0 commit comments

Comments
 (0)