Merge commit from fork

scripts/mlx_image_server.py resolved the model per request
(`req.model or _args.model`) on both /v1/images/generations and
/v1/images/edits, so the caller chose which model was served.

`_is_hidream()` is a substring test and `_snapshot_path()` accepts either a
local directory or a Hugging Face repo id, so a caller-supplied string
selected the HiDream branch and then supplied the directory it runs
`scripts/hidream_o1/generate_hidream_o1_mlx.py` from, under sys.executable.
The server has no auth, and the Cookbook binds it to 0.0.0.0 whenever it is
serving to a remote host, so one POST executed attacker code on the serving
host.

Both paths now use `_args.model`. The request field is still accepted for
OpenAI wire compatibility and ignored, matching scripts/diffusion_server.py,
and Odysseus already sends the served model's own id, so this is a no-op for
legitimate callers. /v1/images/harmonize already pinned.

Regression tests cover both endpoints, the local-directory and
Hugging-Face-repo halves, and that a server actually launched with a HiDream
model still serves it. Three of the four fail on the unfixed code.
This commit is contained in:
nopoz
2026-08-24 17:38:40 +02:00
committed by GitHub
parent b4d12932a9
commit d0d8edf5d8
2 changed files with 147 additions and 2 deletions
+7 -2
View File
@@ -327,7 +327,12 @@ def list_models():
@app.post("/v1/images/generations")
def generate(req: ImageRequest):
model = req.model or _args.model
# The served model is the one this process was launched with. `req.model`
# is accepted for OpenAI wire compatibility and ignored, matching
# scripts/diffusion_server.py: honouring it would let a caller point the
# generator at any local directory or Hugging Face repo, and the HiDream
# branch runs a python script from inside that directory.
model = _args.model
width, height = _size(req.size)
out_images = []
count = max(1, min(int(req.n or 1), 4))
@@ -393,7 +398,7 @@ async def edit_image(
size: str = Form("1024x1024"),
response_format: str = Form("b64_json"),
):
active_model = model or _args.model
active_model = _args.model # pinned; see generate()
if _is_lama_inpaint(active_model) or _is_ddcolor(active_model):
image_raw = await image.read()
mask_raw = await mask.read() if mask is not None else None