vLLM serves models with an OpenAI-shaped audio API.
Transcription already 422s when file is a
string. Translation uses the same field and did not.
The patch is in
PR 55618.
| Document | HB-AR-2026.8 / public source review, speech-to-text requests |
|---|---|
| What this is | A research note and an opinion. The vLLM project did not hire Hackerbane for this. |
| System | vllm-project/vllm, audio transcription and translation requests |
| Scope | TranscriptionRequest and TranslationRequest file validators |
| Review commit | main @ 6865e67 |
| Upstream | PR 55618 (open) |
| Date | 7 September 2026 |
| Author | Barney Chambers, Hackerbane |
If you have not used vLLM: it is an inference server.
The audio routes take a multipart file.
Transcription already refuses a string in that field
with HTTP 422. Translation did not.
On main at commit 6865e67:
# transcription
if isinstance(data.get("file"), str):
raise HTTPException(status_code=422, detail="... not 'str'.")
# translation
# stream options and vllm_xargs only
I opened a patch that copies the transcription check. It is PR 55618. The vLLM project did not hire this review. The name on the cover names the project I read.
Their SECURITY.md lets moderate and low fixes land as public PRs. This is a validator miss, not remote code execution.
| # | ID | Action | Status on 7 Sep 2026 |
|---|---|---|---|
| 1 | MED-01 | Use the same string-file 422 on translation that transcription already uses. | Patch open. PR 55618. |
This is not a full audit of vLLM. I split serving
paths and read media URL allowlists, LoRA unload, MCP,
and speech-to-text. Redirect re-validation and LoRA
engine unload already have open PRs. The finding I
can prove with a unit test on current
main, and that was not already patched,
is the translation file check.
| In scope |
vllm/entrypoints/speech_to_text/transcription/protocol.py
and
translation/protocol.py.
Test in
tests/entrypoints/speech_to_text/test_audio_request_file_type.py.
|
|---|---|
| Out of scope |
Attention kernels. Media-domain redirect hops
(open PR 55539). LoRA engine unload (open PRs).
SageMaker /adapters auth. Realtime
WebSocket size units.
|
| Method |
Compare the two model_validator
methods. Add a parametrized
model_validate({"file": "not-a-file.wav"})
case that fails on 6865e67 for
translation and passes with the patch.
|
| Retest |
pytest tests/entrypoints/speech_to_text/test_audio_request_file_type.py -q
|
| ID | Severity | Title | Status |
|---|---|---|---|
| MED-01 | Medium | translation skips the transcription string-file check | Patch open (PR 55618) |
I called this Medium, not High, because a bad
file still fails later. The miss is the
sibling validator, not a silent success.
vllm/entrypoints/speech_to_text/translation/protocol.py · validate_stream_options
Transcription comments that file must
be a file-like object, then 422s a string.
Translation copies the stream-option half of that
validator and skips the file check. After the
patch both
model_validate({"file": "not-a-file.wav"})
calls raise the same 422.
| When | What |
|---|---|
| 7 Sep 2026 |
Review commit 6865e67. MED-01 confirmed.
Translation missed the string-file 422.
|
| 7 Sep 2026 | Opened PR 55618. Still open when this note was written. |
To retest MED-01, run the command in section 2.
Read this before you treat anything above as advice.
This file is a public research note. The vLLM project did not hire Hackerbane. There is no services agreement, statement of work, or client relationship behind it. The vLLM name on the cover names the project I read. It is not a partnership badge.
What you have is an opinion about the files and commits named in section 2. It is not a certificate. It is not an endorsement of vLLM or of the patch. It is not a claim that the rest of vLLM is safe, or that it is broken.
I am not telling you to merge, deploy, buy, or sell anything. This is not investment advice, legal advice, or a security guarantee. If you ship software, you own that risk. If you run vLLM audio routes, you own that risk.
Hackerbane and I accept no liability for how anyone uses this note, for bugs it does not name, or for loss that follows from relying on it. Findings can be wrong, incomplete, or already stale the day after the review commit. Code added after that commit was not reviewed. A retest covers only the checks it names.
You may share this file. Sharing it does not create a contract and does not make the reader a client.
This note is provided as-is, as available, with all faults. To the maximum extent the law allows, Hackerbane disclaims every warranty, express or implied, including merchantability, fitness for a particular purpose, title, and non-infringement. No promise that this text is accurate, complete, or free of error, or that any error will be fixed.
Nobody may rely on this note as a professional engagement. It is not financial, tax, legal, or regulatory advice. No third party is a beneficiary of it.
| Critical | Someone could steal funds or hurt people with what I looked at. |
|---|---|
| High | The check you think you have does not work in the common case. |
| Medium | A real miss, less common in the output I care about here. |
| Low | Real, but limited, or it needs an unlikely setup. |
| Informational | On the record. Not scored as a bug. |
The coloured bars are labels. The word High or Medium is what counts.