{"schema":"threatline.record/2","record":{"id":"GHSA-r45p-7qwx-qwjw","aliases":["GHSA-r45p-7qwx-qwjw"],"summary":"Multimodal chat audio decoding bypasses the decompression-bomb duration limit","details":"## Summary\n\nMultimodal chat audio decoding bypasses the decompression-bomb duration limit.\n\n## Technical Details\n\nvLLM's current head contains the fix for `GHSA-6pr9-rp53-2pmc` / `CVE-2026-54233`, which adds `VLLM_MAX_AUDIO_DECODE_DURATION_S` and wires that decoded-duration guard into the `/v1/audio/transcriptions` preprocessing path. The same decoded-size guard is not applied to the shared multimodal `AudioMediaIO` path used by OpenAI chat audio inputs.\n\nAs a result, `/v1/chat/completions` requests containing `input_audio` data URLs or `audio_url` media can still reach `AudioMediaIO.load_bytes()` and `AudioMediaIO.load_file()`, both of which call `load_audio(..., sr=None)` with no `max_duration_s` bound. The decoder now supports metadata and decoded-sample duration limits, but the chat media path never passes the limit.\n\nThis is a sibling/incomplete-fix variant of the published audio decompression-bomb issue. The published advisory and fix PR are scoped to speech-to-text; this report covers the separate multimodal chat audio ingestion path.\n\nThe decoder fix added duration-limit support to `load_audio()`, `load_audio_soundfile()`, and `load_audio_pyav()`.\n\nThe speech-to-text path uses that guard:\n\n```python\ny, sr = load_audio(\n    buf,\n    sr=self.asr_config.sample_rate,\n    max_duration_s=self.max_audio_decode_duration_s,\n)\n```\n\nThe chat multimodal path does not:\n\n```python\ndef load_bytes(self, data: bytes) -> tuple[npt.NDArray, float]:\n    return load_audio(BytesIO(data), sr=None)\n\ndef load_file(self, filepath: Path) -> tuple[npt.NDArray, float]:\n    return load_audio(filepath, sr=None)\n```\n\n`MediaConnector.fetch_audio()` constructs `AudioMediaIO`, and `chat_utils.py` routes both `audio_url` and `input_audio` content parts to this path.\n\nThe merged speech-to-text fix PR explicitly left existing callers unaffected because `max_duration_s` defaults to `None`. `AudioMediaIO` is one of those callers and still invokes the decoder without opting in to the guard.\n\n## Impact\n\nMedium\n\n- CWE-409: Improper Handling of Highly Compressed Data (Data Amplification)\n\n```text\nCVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:U/C:N/I:N/A:H\n```\n\nAn attacker who can submit chat completion requests to an audio-capable vLLM deployment can provide a small compressed audio input that expands to very large decoded PCM. The decoder accumulates decoded frames before model-level audio clip limits run, which can exhaust memory or materially degrade availability.\n\nThis does not require a large request body when the payload is supplied as an `audio_url`, and the `input_audio` path is also affected for compressed audio that fits within normal request size limits.\n\n`--allowed-media-domains`, media fetch timeouts, and HTTP body limits may reduce some delivery options, but they do not enforce a decoded PCM duration/sample budget. The issue remains reachable for allowed `audio_url` domains and for `input_audio` data that fits within normal request limits.\n\nThis report uses Medium / `PR:L` to match vLLM's prior audio decompression-bomb advisory and vLLM's policy category for DoS-only issues. If a deployment exposes chat completions without API-key authentication, the same technical issue may be assessed with `PR:N`.\n\n## Suggested Fix\n\nApply the decoder duration guard inside `AudioMediaIO`, not only in the speech-to-text endpoint:\n\n- add a validated `max_duration_s` field to `AudioMediaIO`;\n- default it to `envs.VLLM_MAX_AUDIO_DECODE_DURATION_S`;\n- pass it from `load_bytes()` and `load_file()` into `load_audio(...)`;\n- prevent untrusted request-level `media_io_kwargs[\"audio\"]` from disabling or raising the server-side cap beyond operator policy;\n- add regression coverage for `AudioMediaIO`, `MediaConnector.fetch_audio()`, and chat `input_audio`/`audio_url`.\n\n## Affected Package/Versions\n\n- Ecosystem: pip\n- Package: vllm\n- Confirmed affected range: `>= 0.19.0, < 0.24.0`\n- Patched version: `0.24.0`\n\n## Appendix: Evidence Files\n\n- `report.md`\n- `validation.md`\n- `duplicate-research.md`\n- `severity-and-intended-behavior-validation.md`\n- `suggested-fix.md`\n","categories":["Unclassified"],"product":"vllm","vendor":"","ecosystem":null,"affected_ranges":[{"source":"GitHub Advisory Database","source_url":"https://github.com/vllm-project/vllm/security/advisories/GHSA-r45p-7qwx-qwjw","source_modified_at":"2026-10-09T07:55:16Z","fetched_at":"2026-10-28T15:55:58.673066Z","package":{"ecosystem":"pip","name":"vllm"},"range":">= 0.19.0, < 0.24.0"}],"fixed_versions":[{"source":"GitHub Advisory Database","source_url":"https://github.com/vllm-project/vllm/security/advisories/GHSA-r45p-7qwx-qwjw","source_modified_at":"2026-10-09T07:55:16Z","fetched_at":"2026-10-28T15:55:58.673066Z","package":{"ecosystem":"pip","name":"vllm"},"version":"0.24.0"}],"cvss":6.5,"severity":"Medium","kev":{"listed":false},"epss":{"probability":null,"percentile":null,"score_date":null},"published_at":"2026-10-09T07:55:16Z","modified_at":"2026-10-09T07:55:16Z","provenance":[{"source":"GitHub Advisory Database","url":"https://github.com/vllm-project/vllm/security/advisories/GHSA-r45p-7qwx-qwjw","fetched_at":"2026-10-28T15:55:58.673066Z","source_modified_at":"2026-10-09T07:55:16Z"}],"sources":["GitHub Advisory Database"],"references":[],"locations":[],"motoko_assessment":{"status":"requires_architecture_review","automatic_remediation":false},"classification":{"method":"product-first software-layer rules","rules_version":"2.1","matched_on":null,"confidence":"unknown","reviewed":false},"change_timestamp":"2026-10-09T07:55:16Z","content_hash":"b3ec47a221dec88f5e510a832f8e9fc655b0c7893dc908ded4a746e110d9a341"}}
