diff --git a/Cargo.lock b/Cargo.lock index 26af1d7..7916826 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -481,7 +481,7 @@ dependencies = [ [[package]] name = "mt5-quant" -version = "1.32.2" +version = "1.32.1" dependencies = [ "anyhow", "base64", diff --git a/src/pipeline/backtest.rs b/src/pipeline/backtest.rs index 1fa23ea..39f3561 100644 --- a/src/pipeline/backtest.rs +++ b/src/pipeline/backtest.rs @@ -823,12 +823,12 @@ impl BacktestPipeline { }; let set_file_line = params.set_file.as_ref() - .map(|p| format!("ExpertParameters={}\n", p)) + .map(|p| format!("ExpertParameters={}\n", Self::ini_safe(p))) .unwrap_or_default(); let updates: &[(&str, String)] = &[ - ("Expert", expert_path), - ("Symbol", params.symbol.clone()), + ("Expert", Self::ini_safe(&expert_path)), + ("Symbol", Self::ini_safe(¶ms.symbol)), ("Period", period.to_string()), ("DateRange", "3".into()), ("DateFrom", from_ts.to_string()), @@ -855,6 +855,11 @@ impl BacktestPipeline { Ok(()) } + /// Strip CR/LF from a user-supplied INI value to prevent newline injection. + fn ini_safe(value: &str) -> String { + value.replace(['\n', '\r'], "") + } + fn patch_ini_section(text: &str, section: &str, updates: &[(&str, String)]) -> String { let section_header = format!("[{}]", section); let mut result = String::with_capacity(text.len() + 256); @@ -1025,9 +1030,9 @@ impl BacktestPipeline { ini.push_str("[Tester]\n"); // Expert path is relative to MQL5/Experts/ in the /config: format (no "Experts\" prefix). - ini.push_str(&format!("Expert={}\n", self.resolve_backtest_ini_expert_path(¶ms.expert))); - ini.push_str(&format!("Symbol={}\n", params.symbol)); - ini.push_str(&format!("Period={}\n", params.timeframe)); + ini.push_str(&format!("Expert={}\n", Self::ini_safe(&self.resolve_backtest_ini_expert_path(¶ms.expert)))); + ini.push_str(&format!("Symbol={}\n", Self::ini_safe(¶ms.symbol))); + ini.push_str(&format!("Period={}\n", Self::ini_safe(¶ms.timeframe))); ini.push_str("Optimization=0\n"); ini.push_str(&format!("Model={}\n", params.model)); ini.push_str(&format!("FromDate={}\n", params.from_date)); @@ -1044,7 +1049,7 @@ impl BacktestPipeline { ini.push_str(&format!("ShutdownTerminal={}\n", if params.shutdown { "1" } else { "0" })); if let Some(set_file) = ¶ms.set_file { - ini.push_str(&format!("ExpertParameters={}\n", set_file)); + ini.push_str(&format!("ExpertParameters={}\n", Self::ini_safe(set_file))); } Ok(ini)