Skip to content

Commit bfa25a1

Browse files
Fix CVE-2026-5843: gate model_file execution behind trust_remote_code (ml-explore#1385)
Co-authored-by: Angelos Katharopoulos <a_katharopoulos@apple.com>
1 parent df48987 commit bfa25a1

16 files changed

Lines changed: 222 additions & 27 deletions

mlx_lm/benchmark.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,6 +73,11 @@ def setup_arg_parser():
7373
default=0,
7474
help="Delay between each test in seconds (default: 0)",
7575
)
76+
parser.add_argument(
77+
"--trust-remote-code",
78+
action="store_true",
79+
help="Enable trusting remote code for tokenizer/model loading.",
80+
)
7681
return parser
7782

7883

@@ -94,14 +99,19 @@ def rprint(*args, **kwargs):
9499

95100
if group.size() > 1:
96101
model, tokenizer, config = sharded_load(
97-
model_path, pipeline_group, tensor_group, return_config=True
102+
model_path,
103+
pipeline_group,
104+
tensor_group,
105+
return_config=True,
106+
trust_remote_code=args.trust_remote_code,
98107
)
99108
else:
100109
model, tokenizer, config = load(
101110
model_path,
102111
return_config=True,
103112
tokenizer_config={"trust_remote_code": True},
104113
model_config={"quantize_activations": args.quantize_activations},
114+
trust_remote_code=args.trust_remote_code,
105115
)
106116

107117
# Empty to avoid early stopping

mlx_lm/cache_prompt.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,14 +85,15 @@ def main():
8585
args = parser.parse_args()
8686

8787
# Building tokenizer_config
88-
tokenizer_config = {"trust_remote_code": True if args.trust_remote_code else None}
88+
tokenizer_config = {"trust_remote_code": args.trust_remote_code}
8989
if args.eos_token is not None:
9090
tokenizer_config["eos_token"] = args.eos_token
9191

9292
model, tokenizer = load(
9393
args.model,
9494
adapter_path=args.adapter_path,
9595
tokenizer_config=tokenizer_config,
96+
trust_remote_code=args.trust_remote_code,
9697
)
9798

9899
args.prompt = sys.stdin.read() if args.prompt == "-" else args.prompt

mlx_lm/chat.py

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -102,14 +102,18 @@ def main():
102102
if group.size() > 1:
103103
if args.adapter_path:
104104
parser.error("Adapters not supported in distributed mode")
105-
model, tokenizer = sharded_load(args.model, pipeline_group, tensor_group)
105+
model, tokenizer = sharded_load(
106+
args.model,
107+
pipeline_group,
108+
tensor_group,
109+
trust_remote_code=args.trust_remote_code,
110+
)
106111
else:
107112
model, tokenizer = load(
108113
args.model,
109114
adapter_path=args.adapter_path,
110-
tokenizer_config={
111-
"trust_remote_code": True if args.trust_remote_code else None
112-
},
115+
tokenizer_config={"trust_remote_code": args.trust_remote_code},
116+
trust_remote_code=args.trust_remote_code,
113117
)
114118

115119
with ChatUI(args, rank=rank) as ui:

mlx_lm/convert.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -115,6 +115,7 @@ def convert(
115115
return_config=True,
116116
tokenizer_config={"trust_remote_code": trust_remote_code},
117117
lazy=True,
118+
trust_remote_code=trust_remote_code,
118119
)
119120

120121
if isinstance(quant_predicate, str):

mlx_lm/evaluate.py

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -83,9 +83,11 @@ def __init__(
8383
sampler: Optional[Callable[[mx.array], mx.array]] = None,
8484
) -> None:
8585
super().__init__()
86-
tokenizer_config = {"trust_remote_code": True if trust_remote_code else None}
86+
tokenizer_config = {"trust_remote_code": trust_remote_code}
8787
self._model, self.tokenizer = load(
88-
path_or_hf_repo, tokenizer_config=tokenizer_config
88+
path_or_hf_repo,
89+
tokenizer_config=tokenizer_config,
90+
trust_remote_code=trust_remote_code,
8991
)
9092
self._max_tokens = max_tokens
9193
self._batch_size = batch_size

mlx_lm/fuse.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ def parse_arguments() -> argparse.Namespace:
5454
default="ggml-model-f16.gguf",
5555
type=str,
5656
)
57+
parser.add_argument(
58+
"--trust-remote-code",
59+
action="store_true",
60+
help="Enable trusting remote code for tokenizer/model loading.",
61+
)
5762
return parser.parse_args()
5863

5964

@@ -62,7 +67,10 @@ def main() -> None:
6267
args = parse_arguments()
6368

6469
model, tokenizer, config = load(
65-
args.model, adapter_path=args.adapter_path, return_config=True
70+
args.model,
71+
adapter_path=args.adapter_path,
72+
return_config=True,
73+
trust_remote_code=args.trust_remote_code,
6674
)
6775

6876
fused_linears = [

mlx_lm/generate.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1991,7 +1991,7 @@ def main():
19911991
tokenizer_config = (
19921992
{} if not using_cache else json.loads(metadata["tokenizer_config"])
19931993
)
1994-
tokenizer_config["trust_remote_code"] = True if args.trust_remote_code else None
1994+
tokenizer_config["trust_remote_code"] = args.trust_remote_code
19951995

19961996
model_path = args.model
19971997
if using_cache:
@@ -2010,6 +2010,7 @@ def main():
20102010
adapter_path=args.adapter_path,
20112011
tokenizer_config=tokenizer_config,
20122012
model_config={"quantize_activations": args.quantize_activations},
2013+
trust_remote_code=args.trust_remote_code,
20132014
)
20142015
for eos_token in args.extra_eos_token:
20152016
tokenizer.add_eos_token(eos_token)

mlx_lm/lora.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,7 @@
7777
"mask_prompt": False,
7878
"report_to": None,
7979
"project_name": None,
80+
"trust_remote_code": False,
8081
}
8182

8283

@@ -212,6 +213,11 @@ def build_parser():
212213
help="Project name for logging. Defaults to the name of the root directory.",
213214
)
214215
parser.add_argument("--seed", type=int, help="The PRNG seed")
216+
parser.add_argument(
217+
"--trust-remote-code",
218+
action="store_true",
219+
help="Enable trusting remote code for tokenizer/model loading.",
220+
)
215221
return parser
216222

217223

@@ -338,7 +344,11 @@ def run(args, training_callback: TrainingCallback = None):
338344
)
339345

340346
rprint("Loading pretrained model")
341-
model, tokenizer = load(args.model, tokenizer_config={"trust_remote_code": True})
347+
model, tokenizer = load(
348+
args.model,
349+
tokenizer_config={"trust_remote_code": args.trust_remote_code},
350+
trust_remote_code=args.trust_remote_code,
351+
)
342352

343353
rprint("Loading datasets")
344354
train_set, valid_set, test_set = load_dataset(args, tokenizer)

mlx_lm/perplexity.py

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -144,8 +144,12 @@ def main():
144144

145145
# Load model
146146
print(f"Loading model from {args.model}...")
147-
tokenizer_config = {"trust_remote_code": True if args.trust_remote_code else None}
148-
model, tokenizer = load(args.model, tokenizer_config=tokenizer_config)
147+
tokenizer_config = {"trust_remote_code": args.trust_remote_code}
148+
model, tokenizer = load(
149+
args.model,
150+
tokenizer_config=tokenizer_config,
151+
trust_remote_code=args.trust_remote_code,
152+
)
149153

150154
# Count parameters
151155
total_params = get_total_parameters(model)

mlx_lm/quant/awq.py

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -544,6 +544,11 @@ def main():
544544
parser.add_argument("--sequence-length", type=int, default=512)
545545
parser.add_argument("--n-grid", type=int, default=20)
546546
parser.add_argument("--seed", type=int, default=123)
547+
parser.add_argument(
548+
"--trust-remote-code",
549+
action="store_true",
550+
help="Enable trusting remote code for tokenizer/model loading.",
551+
)
547552
args = parser.parse_args()
548553

549554
group = mx.distributed.init()
@@ -554,7 +559,12 @@ def main():
554559

555560
mx.random.seed(args.seed)
556561

557-
model, tokenizer, config = load(args.model, lazy=True, return_config=True)
562+
model, tokenizer, config = load(
563+
args.model,
564+
lazy=True,
565+
return_config=True,
566+
trust_remote_code=args.trust_remote_code,
567+
)
558568

559569
model_type = config["model_type"]
560570
if (awq_config := AWQ_MODEL_CONFIGS.get(model_type, None)) is None:

0 commit comments

Comments
 (0)