Skip to content

Fix code injection (CWE-94) in PythonInitializer and argument injection (CWE-88) in ConsoleLeanOptimizer#9506

Closed
alanturing881 wants to merge 1 commit into
QuantConnect:masterfrom
alanturing881:fix/code-injection-python-path-and-optimizer-args
Closed

Fix code injection (CWE-94) in PythonInitializer and argument injection (CWE-88) in ConsoleLeanOptimizer#9506
alanturing881 wants to merge 1 commit into
QuantConnect:masterfrom
alanturing881:fix/code-injection-python-path-and-optimizer-args

Conversation

@alanturing881
Copy link
Copy Markdown

Security Fix — Code Injection (CWE-94) + Argument Injection (CWE-88)

Summary

  • CWE-94 — Python code injection via unsanitized path in PythonInitializer.AddPythonPaths()
  • CWE-88 — Argument injection via unquoted {parameterSet} in ConsoleLeanOptimizer.RunLean()

VULN-001 — Python Code Injection (Common/Python/PythonInitializer.cs:143)

Root cause: Path strings were directly interpolated into a Python code string passed to PythonEngine.Exec(). On Linux, directory names can contain newlines and single quotes — both of which allow breaking out of the string literal and injecting arbitrary Python code.

// Before (vulnerable)
var code = string.Join(";", _pendingPathAdditions
    .Select(s => $"sys.path.insert({{insertionIndex}}, '{{s}}')")).Replace('\\', '/');
PythonEngine.Exec(code, locals: locals);

Fix: Pass each path as a PyString object directly via the Python.NET API — no string interpolation needed, no injection possible.

// After (safe)
foreach (var path in _pendingPathAdditions)
{
    using var pyPath = new PyString(path.Replace('\\', '/'));
    sys.path.insert(insertionIndex, pyPath);
}

VULN-002 — Argument Injection (Optimizer.Launcher/ConsoleLeanOptimizer.cs:93)

Root cause: The --parameters {parameterSet} segment was embedded in ProcessStartInfo.Arguments without quoting. Since --parameters is registered as CommandOptionType.MultipleValue in the Lean argument parser, any space-separated token matching a known CLI flag is parsed as a new argument. A StaticOptimizationParameter value containing spaces (e.g., 1 --algorithm-location /evil.py) injects additional arguments into every spawned backtest child process.

// Before (vulnerable)
Arguments = $"... --parameters {parameterSet} --backtest-name \"...\"";

Fix: Use ProcessStartInfo.ArgumentList (.NET 5+) which handles per-argument quoting automatically.

// After (safe)
startInfo.ArgumentList.Add("--parameters");
startInfo.ArgumentList.Add(parameterSet.ToString());

Impact

  • CWE-94: Arbitrary code execution in the Lean Python engine via crafted directory name in python-additional-paths
  • CWE-88: Algorithm substitution in optimizer child processes — unauthorized trading, credential exfiltration, or RCE via loading a malicious algorithm file

Affected versions

All versions <= v2.4.0.1

References

…soleLeanOptimizer

PythonInitializer.AddPythonPaths() (CWE-94): replaced string-interpolated
PythonEngine.Exec() call with direct Python.NET API calls (sys.path.insert via
PyString), eliminating injection risk from paths containing single quotes or newlines.

ConsoleLeanOptimizer.RunLean() (CWE-88): replaced unquoted --parameters {parameterSet}
in ProcessStartInfo.Arguments with ProcessStartInfo.ArgumentList, which handles
per-argument escaping automatically and prevents injection via parameter values
containing spaces and known CLI flag names.

Co-Authored-By: iaohkut <thb2601@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants