From f60f8ec13da746db5d6dc6dfab669fcb318f2248 Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 6 Oct 2026 08:01:45 +0000 Subject: [PATCH 1/2] Fix command injection vulnerability in stdlib/src/process.rs Co-authored-by: Tcode-Motion <188012755+Tcode-Motion@users.noreply.github.com> --- Cargo.lock | 156 +++++++++++-------------------- cli/Cargo.toml | 4 +- compiler/bytecode/Cargo.toml | 4 +- runtime/vm/Cargo.toml | 2 +- stdlib/Cargo.toml | 4 +- stdlib/src/process.rs | 10 +- stdlib/tests/stdlib_tests.rs | 14 +++ tools/package-manager/Cargo.toml | 2 +- 8 files changed, 80 insertions(+), 116 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 182d59ef..0f093484 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -551,12 +551,6 @@ dependencies = [ "serde", ] -[[package]] -name = "bincode" -version = "3.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd6a120d2e16b3e1b4a24bd70f23b12d3e16b81f113364a26935f8db7245452d" - [[package]] name = "bit_field" version = "0.10.3" @@ -947,35 +941,6 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" -[[package]] -name = "cookie" -version = "0.18.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a373e3602691c3cdea496d2f0ee5935151e6168fe87739483c463db1b2f2f87" -dependencies = [ - "percent-encoding", - "time", - "version_check", -] - -[[package]] -name = "cookie_store" -version = "0.22.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "15b2c103cf610ec6cae3da84a766285b42fd16aad564758459e6ecf128c75206" -dependencies = [ - "cookie", - "document-features", - "idna", - "indexmap", - "log", - "serde", - "serde_derive", - "serde_json", - "time", - "url", -] - [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1252,15 +1217,6 @@ dependencies = [ "syn 3.0.3", ] -[[package]] -name = "document-features" -version = "0.2.12" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" -dependencies = [ - "litrs", -] - [[package]] name = "dunce" version = "1.0.5" @@ -1761,16 +1717,6 @@ dependencies = [ "windows-sys 0.61.2", ] -[[package]] -name = "http" -version = "1.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" -dependencies = [ - "bytes", - "itoa", -] - [[package]] name = "httparse" version = "1.10.1" @@ -1798,7 +1744,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcf4dd4c44ae85155502a52c48739c8a48185d1449fff1963cffee63c28a50f0" dependencies = [ - "bincode 1.3.3", + "bincode", "fst", "hyphenation_commons", "pocket-resources", @@ -2139,12 +2085,6 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" -[[package]] -name = "litrs" -version = "1.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" - [[package]] name = "llvm-sys" version = "231.0.0" @@ -3023,13 +2963,24 @@ dependencies = [ "nibble_vec", ] +[[package]] +name = "rand" +version = "0.8.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" +dependencies = [ + "libc", + "rand_chacha 0.3.1", + "rand_core 0.6.4", +] + [[package]] name = "rand" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ - "rand_chacha", + "rand_chacha 0.9.0", "rand_core 0.9.5", ] @@ -3044,6 +2995,16 @@ dependencies = [ "rand_core 0.10.1", ] +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core 0.6.4", +] + [[package]] name = "rand_chacha" version = "0.9.0" @@ -3054,6 +3015,15 @@ dependencies = [ "rand_core 0.9.5", ] +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom 0.2.17", +] + [[package]] name = "rand_core" version = "0.9.5" @@ -3103,7 +3073,7 @@ dependencies = [ "paste", "profiling", "rand 0.9.5", - "rand_chacha", + "rand_chacha 0.9.0", "simd_helpers", "thiserror", "v_frame", @@ -3713,7 +3683,7 @@ dependencies = [ name = "techscript_bytecode" version = "2.0.0" dependencies = [ - "bincode 3.0.0", + "bincode", "serde", "techscript_ast", "techscript_common", @@ -3731,7 +3701,7 @@ name = "techscript_cli" version = "2.0.0" dependencies = [ "anyhow", - "bincode 3.0.0", + "bincode", "clap", "clap_complete", "colored", @@ -4004,7 +3974,7 @@ dependencies = [ "printpdf", "qrcode", "quick-xml 0.42.0", - "rand 0.10.2", + "rand 0.8.8", "rusqlite", "rustls", "serde", @@ -4038,7 +4008,7 @@ dependencies = [ name = "techscript_vm" version = "2.0.0" dependencies = [ - "bincode 3.0.0", + "bincode", "indexmap", "serde", "techscript_ast", @@ -4116,7 +4086,6 @@ dependencies = [ "powerfmt", "serde_core", "time-core", - "time-macros", ] [[package]] @@ -4125,16 +4094,6 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" -[[package]] -name = "time-macros" -version = "0.2.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" -dependencies = [ - "num-conv", - "time-core", -] - [[package]] name = "tiny_http" version = "0.12.0" @@ -4479,34 +4438,20 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "3.4.2" +version = "2.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9a7ac20be9b7726e0bbdbf974c059676d9acb1cd414961f570a4e8231cacd7fc" +checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" dependencies = [ - "base64 0.23.1", - "cookie_store", + "base64 0.22.1", "flate2", "log", - "percent-encoding", + "once_cell", "rustls", "rustls-pki-types", "serde", "serde_json", - "ureq-proto", - "utf8-zero", - "webpki-roots", -] - -[[package]] -name = "ureq-proto" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f86fd172ccca569e458f61b6bdd6220965a9ef36e672a6852953b51a0e1583be" -dependencies = [ - "base64 0.23.1", - "http", - "httparse", - "log", + "url", + "webpki-roots 0.26.11", ] [[package]] @@ -4522,12 +4467,6 @@ dependencies = [ "serde_derive", ] -[[package]] -name = "utf8-zero" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" - [[package]] name = "utf8_iter" version = "1.0.4" @@ -4665,6 +4604,15 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webpki-roots" +version = "0.26.11" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" +dependencies = [ + "webpki-roots 1.0.9", +] + [[package]] name = "webpki-roots" version = "1.0.9" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 68093c36..78bdda33 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -38,10 +38,10 @@ anyhow = { workspace = true } rustyline = { workspace = true } toml = { workspace = true } indexmap = { workspace = true } -bincode = "3.0.0" +bincode = "1.3.3" dirs = "7.0" num_cpus = "1.15" -ureq = "3.4" +ureq = "2.9" rayon = "1.12.0" [build-dependencies] diff --git a/compiler/bytecode/Cargo.toml b/compiler/bytecode/Cargo.toml index 9ea7eef3..b8d2cc9c 100644 --- a/compiler/bytecode/Cargo.toml +++ b/compiler/bytecode/Cargo.toml @@ -11,7 +11,7 @@ techscript_syntax = { path = "../syntax" } techscript_ast = { path = "../ast" } techscript_ir = { path = "../ir" } serde = { workspace = true } -bincode = "3.0.0" +bincode = "1.3.3" [dev-dependencies] techscript_errors = { path = "../errors" } @@ -20,4 +20,4 @@ techscript_parser = { path = "../parser" } techscript_semantic = { path = "../semantic" } techscript_optimizer = { path = "../optimizer" } serde = { workspace = true } -bincode = "3.0.0" +bincode = "1.3.3" diff --git a/runtime/vm/Cargo.toml b/runtime/vm/Cargo.toml index 85be2e86..50cc4cf4 100644 --- a/runtime/vm/Cargo.toml +++ b/runtime/vm/Cargo.toml @@ -15,7 +15,7 @@ techscript_runtime = { path = "../runtime" } techscript_builtins = { path = "../builtins" } techscript_stdlib = { path = "../../stdlib" } serde = { workspace = true } -bincode = "3.0.0" +bincode = "1.3.3" thiserror = { workspace = true } indexmap = "2.0" diff --git a/stdlib/Cargo.toml b/stdlib/Cargo.toml index 2cae9310..f4b1bebf 100644 --- a/stdlib/Cargo.toml +++ b/stdlib/Cargo.toml @@ -10,7 +10,7 @@ techscript_runtime = { path = "../runtime/runtime" } serde_json = { workspace = true } serde = { workspace = true } indexmap = { version = "2", features = ["serde"] } -ureq = { version = "3.4", features = ["json"] } +ureq = { version = "2.9", features = ["json"] } toml = { workspace = true } rusqlite = { version = "0.40", features = ["bundled"] } md5 = "0.8" @@ -24,7 +24,7 @@ flate2 = "1.0" crc = "3.0" image = "0.25" tiny_http = "0.12" -rand = "0.10" +rand = "0.8" zip = "8.6" shlex = "2.0" url = "2.5" diff --git a/stdlib/src/process.rs b/stdlib/src/process.rs index b22f3ee4..c788d815 100644 --- a/stdlib/src/process.rs +++ b/stdlib/src/process.rs @@ -32,10 +32,11 @@ impl StdlibRegistry { )); } let cmd = args[0].try_into_string()?; - if cmd.contains("..") || cmd.contains('\0') { + let forbidden_chars = ['&', '|', ';', '$', '>', '<', '`', '!', '\n', '\r', ' ', '\t']; + if cmd.contains("..") || cmd.contains('\0') || cmd.contains(|c| forbidden_chars.contains(&c)) { return Err(RuntimeError::new( RuntimeErrorKind::InvalidOperation( - "Security policy violation: Path traversal or null bytes in command are denied".to_string(), + "Security policy violation: Path traversal, null bytes, or shell metacharacters in command are denied".to_string(), ), None, None, @@ -124,10 +125,11 @@ impl StdlibRegistry { } }; - if cmd.contains("..") || cmd.contains('\0') { + let forbidden_chars = ['&', '|', ';', '$', '>', '<', '`', '!', '\n', '\r', ' ', '\t']; + if cmd.contains("..") || cmd.contains('\0') || cmd.contains(|c| forbidden_chars.contains(&c)) { return Err(RuntimeError::new( RuntimeErrorKind::InvalidOperation( - "Security policy violation: Path traversal or null bytes in command are denied".to_string(), + "Security policy violation: Path traversal, null bytes, or shell metacharacters in command are denied".to_string(), ), None, None, diff --git a/stdlib/tests/stdlib_tests.rs b/stdlib/tests/stdlib_tests.rs index 0572b5d1..4b28981e 100644 --- a/stdlib/tests/stdlib_tests.rs +++ b/stdlib/tests/stdlib_tests.rs @@ -564,6 +564,20 @@ fn test_system_diagnostics_and_process_execution() { panic!("disk did not return a Map"); } + // 1.5 Verify command injection protection + let run = process.exports.get("run").unwrap(); + let res = run.call( + &mut ctx, + vec![ + RuntimeValue::Str("echo; ls".to_string()), + RuntimeValue::List { + items: std::rc::Rc::new(std::cell::RefCell::new(vec![])), + is_const: false, + }, + ], + ); + assert!(res.is_err()); + // 2. Process run under granted Capability::Process let run = process.exports.get("run").unwrap(); let cmd = if cfg!(windows) { "cmd" } else { "echo" }; diff --git a/tools/package-manager/Cargo.toml b/tools/package-manager/Cargo.toml index 53577487..6f3e0b77 100644 --- a/tools/package-manager/Cargo.toml +++ b/tools/package-manager/Cargo.toml @@ -10,7 +10,7 @@ serde = { workspace = true } serde_json = { workspace = true } toml = "1.1" anyhow = { workspace = true } -ureq = "3.4" +ureq = "2.9" [[bench]] name = "capability_validation_bench" From 9b626235582d8a78ca236d4bd33d4687213b42ea Mon Sep 17 00:00:00 2001 From: "google-labs-jules[bot]" <161369871+google-labs-jules[bot]@users.noreply.github.com> Date: Tue, 6 Oct 2026 08:23:28 +0000 Subject: [PATCH 2/2] Fix command injection vulnerability in process execution Co-authored-by: Tcode-Motion <188012755+Tcode-Motion@users.noreply.github.com> --- Cargo.lock | 156 ++++++++++++++++++++----------- cli/Cargo.toml | 4 +- compiler/bytecode/Cargo.toml | 4 +- runtime/vm/Cargo.toml | 2 +- stdlib/Cargo.toml | 4 +- stdlib/src/process.rs | 32 +++++-- stdlib/tests/stdlib_tests.rs | 14 +-- tools/package-manager/Cargo.toml | 2 +- 8 files changed, 145 insertions(+), 73 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 0f093484..182d59ef 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -551,6 +551,12 @@ dependencies = [ "serde", ] +[[package]] +name = "bincode" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6a120d2e16b3e1b4a24bd70f23b12d3e16b81f113364a26935f8db7245452d" + [[package]] name = "bit_field" version = "0.10.3" @@ -941,6 +947,35 @@ version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3d52eff69cd5e647efe296129160853a42795992097e8af39800e1060caeea9b" +[[package]] +name = "cookie" +version = "0.18.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1a373e3602691c3cdea496d2f0ee5935151e6168fe87739483c463db1b2f2f87" +dependencies = [ + "percent-encoding", + "time", + "version_check", +] + +[[package]] +name = "cookie_store" +version = "0.22.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "15b2c103cf610ec6cae3da84a766285b42fd16aad564758459e6ecf128c75206" +dependencies = [ + "cookie", + "document-features", + "idna", + "indexmap", + "log", + "serde", + "serde_derive", + "serde_json", + "time", + "url", +] + [[package]] name = "core-foundation-sys" version = "0.8.7" @@ -1217,6 +1252,15 @@ dependencies = [ "syn 3.0.3", ] +[[package]] +name = "document-features" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d4b8a88685455ed29a21542a33abd9cb6510b6b129abadabdcef0f4c55bc8f61" +dependencies = [ + "litrs", +] + [[package]] name = "dunce" version = "1.0.5" @@ -1717,6 +1761,16 @@ dependencies = [ "windows-sys 0.61.2", ] +[[package]] +name = "http" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "918d3568bebf352712bc2ef3d46a8bcf1a75b373be6539de198e9105cbbf9ce0" +dependencies = [ + "bytes", + "itoa", +] + [[package]] name = "httparse" version = "1.10.1" @@ -1744,7 +1798,7 @@ version = "0.8.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bcf4dd4c44ae85155502a52c48739c8a48185d1449fff1963cffee63c28a50f0" dependencies = [ - "bincode", + "bincode 1.3.3", "fst", "hyphenation_commons", "pocket-resources", @@ -2085,6 +2139,12 @@ version = "0.8.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "47d9d19d1d6efa0109d2f65ff4c85cddd50bd572e5a00127ab10987290bcefae" +[[package]] +name = "litrs" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11d3d7f243d5c5a8b9bb5d6dd2b1602c0cb0b9db1621bafc7ed66e35ff9fe092" + [[package]] name = "llvm-sys" version = "231.0.0" @@ -2963,24 +3023,13 @@ dependencies = [ "nibble_vec", ] -[[package]] -name = "rand" -version = "0.8.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e058c7de0b26af77780c769414d6257830bb240f3c38477dbc2c16e5f54d6d4c" -dependencies = [ - "libc", - "rand_chacha 0.3.1", - "rand_core 0.6.4", -] - [[package]] name = "rand" version = "0.9.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b9ef1d0d795eb7d84685bca4f72f3649f064e6641543d3a8c415898726a57b41" dependencies = [ - "rand_chacha 0.9.0", + "rand_chacha", "rand_core 0.9.5", ] @@ -2995,16 +3044,6 @@ dependencies = [ "rand_core 0.10.1", ] -[[package]] -name = "rand_chacha" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" -dependencies = [ - "ppv-lite86", - "rand_core 0.6.4", -] - [[package]] name = "rand_chacha" version = "0.9.0" @@ -3015,15 +3054,6 @@ dependencies = [ "rand_core 0.9.5", ] -[[package]] -name = "rand_core" -version = "0.6.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" -dependencies = [ - "getrandom 0.2.17", -] - [[package]] name = "rand_core" version = "0.9.5" @@ -3073,7 +3103,7 @@ dependencies = [ "paste", "profiling", "rand 0.9.5", - "rand_chacha 0.9.0", + "rand_chacha", "simd_helpers", "thiserror", "v_frame", @@ -3683,7 +3713,7 @@ dependencies = [ name = "techscript_bytecode" version = "2.0.0" dependencies = [ - "bincode", + "bincode 3.0.0", "serde", "techscript_ast", "techscript_common", @@ -3701,7 +3731,7 @@ name = "techscript_cli" version = "2.0.0" dependencies = [ "anyhow", - "bincode", + "bincode 3.0.0", "clap", "clap_complete", "colored", @@ -3974,7 +4004,7 @@ dependencies = [ "printpdf", "qrcode", "quick-xml 0.42.0", - "rand 0.8.8", + "rand 0.10.2", "rusqlite", "rustls", "serde", @@ -4008,7 +4038,7 @@ dependencies = [ name = "techscript_vm" version = "2.0.0" dependencies = [ - "bincode", + "bincode 3.0.0", "indexmap", "serde", "techscript_ast", @@ -4086,6 +4116,7 @@ dependencies = [ "powerfmt", "serde_core", "time-core", + "time-macros", ] [[package]] @@ -4094,6 +4125,16 @@ version = "0.1.9" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109" +[[package]] +name = "time-macros" +version = "0.2.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e689342a48d2ea927c87ea50cabf8594854bf940e9310208848d680d668ed85" +dependencies = [ + "num-conv", + "time-core", +] + [[package]] name = "tiny_http" version = "0.12.0" @@ -4438,20 +4479,34 @@ checksum = "8ecb6da28b8a351d773b68d5825ac39017e680750f980f3a1a85cd8dd28a47c1" [[package]] name = "ureq" -version = "2.12.1" +version = "3.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "02d1a66277ed75f640d608235660df48c8e3c19f3b4edb6a263315626cc3c01d" +checksum = "9a7ac20be9b7726e0bbdbf974c059676d9acb1cd414961f570a4e8231cacd7fc" dependencies = [ - "base64 0.22.1", + "base64 0.23.1", + "cookie_store", "flate2", "log", - "once_cell", + "percent-encoding", "rustls", "rustls-pki-types", "serde", "serde_json", - "url", - "webpki-roots 0.26.11", + "ureq-proto", + "utf8-zero", + "webpki-roots", +] + +[[package]] +name = "ureq-proto" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f86fd172ccca569e458f61b6bdd6220965a9ef36e672a6852953b51a0e1583be" +dependencies = [ + "base64 0.23.1", + "http", + "httparse", + "log", ] [[package]] @@ -4467,6 +4522,12 @@ dependencies = [ "serde_derive", ] +[[package]] +name = "utf8-zero" +version = "0.8.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8c0a043c9540bae7c578c88f91dda8bd82e59ae27c21baca69c8b191aaf5a6e" + [[package]] name = "utf8_iter" version = "1.0.4" @@ -4604,15 +4665,6 @@ dependencies = [ "wasm-bindgen", ] -[[package]] -name = "webpki-roots" -version = "0.26.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "521bc38abb08001b01866da9f51eb7c5d647a19260e00054a8c7fd5f9e57f7a9" -dependencies = [ - "webpki-roots 1.0.9", -] - [[package]] name = "webpki-roots" version = "1.0.9" diff --git a/cli/Cargo.toml b/cli/Cargo.toml index 78bdda33..68093c36 100644 --- a/cli/Cargo.toml +++ b/cli/Cargo.toml @@ -38,10 +38,10 @@ anyhow = { workspace = true } rustyline = { workspace = true } toml = { workspace = true } indexmap = { workspace = true } -bincode = "1.3.3" +bincode = "3.0.0" dirs = "7.0" num_cpus = "1.15" -ureq = "2.9" +ureq = "3.4" rayon = "1.12.0" [build-dependencies] diff --git a/compiler/bytecode/Cargo.toml b/compiler/bytecode/Cargo.toml index b8d2cc9c..9ea7eef3 100644 --- a/compiler/bytecode/Cargo.toml +++ b/compiler/bytecode/Cargo.toml @@ -11,7 +11,7 @@ techscript_syntax = { path = "../syntax" } techscript_ast = { path = "../ast" } techscript_ir = { path = "../ir" } serde = { workspace = true } -bincode = "1.3.3" +bincode = "3.0.0" [dev-dependencies] techscript_errors = { path = "../errors" } @@ -20,4 +20,4 @@ techscript_parser = { path = "../parser" } techscript_semantic = { path = "../semantic" } techscript_optimizer = { path = "../optimizer" } serde = { workspace = true } -bincode = "1.3.3" +bincode = "3.0.0" diff --git a/runtime/vm/Cargo.toml b/runtime/vm/Cargo.toml index 50cc4cf4..85be2e86 100644 --- a/runtime/vm/Cargo.toml +++ b/runtime/vm/Cargo.toml @@ -15,7 +15,7 @@ techscript_runtime = { path = "../runtime" } techscript_builtins = { path = "../builtins" } techscript_stdlib = { path = "../../stdlib" } serde = { workspace = true } -bincode = "1.3.3" +bincode = "3.0.0" thiserror = { workspace = true } indexmap = "2.0" diff --git a/stdlib/Cargo.toml b/stdlib/Cargo.toml index f4b1bebf..2cae9310 100644 --- a/stdlib/Cargo.toml +++ b/stdlib/Cargo.toml @@ -10,7 +10,7 @@ techscript_runtime = { path = "../runtime/runtime" } serde_json = { workspace = true } serde = { workspace = true } indexmap = { version = "2", features = ["serde"] } -ureq = { version = "2.9", features = ["json"] } +ureq = { version = "3.4", features = ["json"] } toml = { workspace = true } rusqlite = { version = "0.40", features = ["bundled"] } md5 = "0.8" @@ -24,7 +24,7 @@ flate2 = "1.0" crc = "3.0" image = "0.25" tiny_http = "0.12" -rand = "0.8" +rand = "0.10" zip = "8.6" shlex = "2.0" url = "2.5" diff --git a/stdlib/src/process.rs b/stdlib/src/process.rs index c788d815..a5d75c88 100644 --- a/stdlib/src/process.rs +++ b/stdlib/src/process.rs @@ -32,11 +32,21 @@ impl StdlibRegistry { )); } let cmd = args[0].try_into_string()?; - let forbidden_chars = ['&', '|', ';', '$', '>', '<', '`', '!', '\n', '\r', ' ', '\t']; - if cmd.contains("..") || cmd.contains('\0') || cmd.contains(|c| forbidden_chars.contains(&c)) { + let shell_interpreters = [ + "sh", "bash", "zsh", "csh", "ksh", "dash", "ash", "tcsh", + "powershell", "pwsh", "cmd", "cmd.exe", "bat", "ps1" + ]; + let cmd_lower = cmd.to_lowercase(); + let is_shell = shell_interpreters.iter().any(|&s| { + cmd_lower == s + || cmd_lower.ends_with(&format!("/{}", s)) + || cmd_lower.ends_with(&format!("\\{}", s)) + }); + + if cmd.contains("..") || cmd.contains('\0') || is_shell { return Err(RuntimeError::new( RuntimeErrorKind::InvalidOperation( - "Security policy violation: Path traversal, null bytes, or shell metacharacters in command are denied".to_string(), + "Security policy violation: Path traversal, null bytes, or shell interpreters in command are denied".to_string(), ), None, None, @@ -125,11 +135,21 @@ impl StdlibRegistry { } }; - let forbidden_chars = ['&', '|', ';', '$', '>', '<', '`', '!', '\n', '\r', ' ', '\t']; - if cmd.contains("..") || cmd.contains('\0') || cmd.contains(|c| forbidden_chars.contains(&c)) { + let shell_interpreters = [ + "sh", "bash", "zsh", "csh", "ksh", "dash", "ash", "tcsh", + "powershell", "pwsh", "cmd", "cmd.exe", "bat", "ps1" + ]; + let cmd_lower = cmd.to_lowercase(); + let is_shell = shell_interpreters.iter().any(|&s| { + cmd_lower == s + || cmd_lower.ends_with(&format!("/{}", s)) + || cmd_lower.ends_with(&format!("\\{}", s)) + }); + + if cmd.contains("..") || cmd.contains('\0') || is_shell { return Err(RuntimeError::new( RuntimeErrorKind::InvalidOperation( - "Security policy violation: Path traversal, null bytes, or shell metacharacters in command are denied".to_string(), + "Security policy violation: Path traversal, null bytes, or shell interpreters in command are denied".to_string(), ), None, None, diff --git a/stdlib/tests/stdlib_tests.rs b/stdlib/tests/stdlib_tests.rs index 4b28981e..5da4565b 100644 --- a/stdlib/tests/stdlib_tests.rs +++ b/stdlib/tests/stdlib_tests.rs @@ -569,9 +569,12 @@ fn test_system_diagnostics_and_process_execution() { let res = run.call( &mut ctx, vec![ - RuntimeValue::Str("echo; ls".to_string()), + RuntimeValue::Str("sh".to_string()), RuntimeValue::List { - items: std::rc::Rc::new(std::cell::RefCell::new(vec![])), + items: std::rc::Rc::new(std::cell::RefCell::new(vec![ + RuntimeValue::Str("-c".to_string()), + RuntimeValue::Str("echo hacked".to_string()), + ])), is_const: false, }, ], @@ -580,12 +583,9 @@ fn test_system_diagnostics_and_process_execution() { // 2. Process run under granted Capability::Process let run = process.exports.get("run").unwrap(); - let cmd = if cfg!(windows) { "cmd" } else { "echo" }; + let cmd = if cfg!(windows) { "whoami" } else { "echo" }; let args = if cfg!(windows) { - vec![ - RuntimeValue::Str("/c".to_string()), - RuntimeValue::Str("echo hello".to_string()), - ] + vec![] } else { vec![RuntimeValue::Str("hello".to_string())] }; diff --git a/tools/package-manager/Cargo.toml b/tools/package-manager/Cargo.toml index 6f3e0b77..53577487 100644 --- a/tools/package-manager/Cargo.toml +++ b/tools/package-manager/Cargo.toml @@ -10,7 +10,7 @@ serde = { workspace = true } serde_json = { workspace = true } toml = "1.1" anyhow = { workspace = true } -ureq = "2.9" +ureq = "3.4" [[bench]] name = "capability_validation_bench"