{"id":"GHSA-894j-wg8m-63h8","kind":"vulnerability","aliases":["GHSA-894j-wg8m-63h8"],"related":[],"title":"vLLM OpenCVDynamicOpenPanguVideoBackend: request-level num_frames without a ceiling — unauthenticated memory/CPU exhaustion (OOM-kill) on any video-capable deployment","description":"## Summary\n\n`OpenCVDynamicOpenPanguVideoBackend` (`vllm/multimodal/video.py:1222-1260`) drives its frame-index computation from the request-controlled `num_frames` with **no ceiling**. The backend is registered without a `video_processor` binding, so no model selects it by default — but `VideoMediaIO` honors request-level `media_io_kwargs.video.video_backend` for any registered **CPU** loader (`merge_kwargs`, `vllm/multimodal/media/video.py:42-90`, strips only `hw_decoders`/`pool_size`/`device`/unconfigured-GPU backends and clamps none of the sampling knobs). One unauthenticated `POST /v1/chat/completions` (or `/tokenize`) with `\"video_backend\": \"openpangu\"` routes any video through this sampler on **any video-capable deployment** — no GLM/OpenPangu model required, no non-default flags, no auth.\n\n## Root cause\n\n```python\nnum_frames = target.num_frames          # request-controlled, unclamped\nfps = target.fps                        # request-controlled\nif fps > 0:\n    if num_frames >= int(total_duration * fps) + 1:\n        num_frames = int(total_duration * fps) + 1   # clamp only fires when ABOVE duration*fps\n...\nsample_frame_timestamps = np.linspace(0, total_duration, num_frames, dtype=float)\nframes_indices = [min(total_frames_num - 1, round(t * original_fps))\n                  for t in sample_frame_timestamps]\n```\n\nThe only clamp fires when `num_frames >= int(duration*fps)+1`. Choosing `num_frames` just below that bound — or `fps=-1`, which skips the branch entirely — leaves the request value untouched: `np.linspace(0, d, num_frames)` allocates `8 × num_frames` bytes and the Python comprehension walks every element, inside the API-server process.\n\nMeasured in-process (official CPU image, `vllm/vllm-openai-cpu:latest` v0.30.0):\n\n- `num_frames=1e7` → 462 MB peak, 118 s CPU\n- `num_frames=1e9` → ~46 GB / hours (linear extrapolation) → OOM-kill\n\nThis is an instance of the published unclamped-`num_frames` family (GHSA-vxqj-p4gw-9h4c; central clamp PR #51969 subsequently superseded by #58830), with two aggravating differences: the sink is a distinct `np.linspace` + list-comprehension allocation, and the backend is reachable via request-level backend selection **without any model opting into it**.\n\n## Suggested fix\n\n- Backend: clamp `num_frames` before `np.linspace` (e.g. `min(num_frames, total_frames_num)` or a class-level cap) and treat `fps=-1` the same.\n- Central: land the `num_frames` clamp in `VideoMediaIO.merge_kwargs` (where PR #51969 is adding it) so per-backend audits stop missing siblings, and consider gating request-level `video_backend` selection to an allowlist.\n\n## Static reach\n\n`vllm/multimodal/media/video.py:42-90` (`merge_kwargs`: no clamp on `num_frames`/`fps`; GPU-only gating for `video_backend`); sink at `vllm/multimodal/video.py:1222-1260`.\n\n## Affected versions\n\n- Package: `vllm` (PyPI).\n- Affected versions: `>= 0.30.0, < 0.31.0`.\n- First stable patched version: `0.31.0`.\n\nPR #58830 blocks untrusted per-request `mm_processor_kwargs` and `media_io_kwargs` by default before preprocessing. Keep `--trust-request-mm-kwargs` disabled for untrusted clients. Explicitly enabling it restores trusted override behavior; the underlying processor/sampler is not independently bounded by this fix.\n\nThe lower bound records the verified affected v0.30.0 release. The backend predates that release; earlier request-path exposure has not been comprehensively assessed.\n\nAdvisory fixed in [#58830](https://github.com/vllm-project/vllm/pull/58830).","summary":"vLLM's OpenCV video backend uses a request-supplied num_frames value with no upper limit, so the frame-index allocation grows with whatever a client sends. An unauthenticated request to the chat completions endpoint that selects this backend can exhaust memory and CPU in the API server process until it is killed.","severity":"medium","cvss":5.3,"epss":null,"exploited":false,"exploited_at":null,"products":[{"name":"vllm","fixed":["0.31.0"],"affected":">= 0.30.0, < 0.31.0","ecosystem":"pypi"}],"ecosystems":["pypi"],"tags":["ai-tooling","cwe-400","cwe-770","multimodal","openai-compatible-api","self-hosted","vllm"],"not_affected_if":["on-vllm-0.31.0-or-later"],"how_to_check":"- Check the installed version with `pip show vllm`; versions `>= 0.30.0` and `< 0.31.0` are affected.\n- Check whether the server was launched with `--trust-request-mm-kwargs`; the advisory says to keep it disabled for untrusted clients.\n- Check whether the deployment accepts video input at all, since any video-capable deployment is reachable.","fix":"- vLLM: move to `0.31.0` or later.\n- Keep `--trust-request-mm-kwargs` disabled for untrusted clients.","status":"open","published_at":"2026-10-27T22:24:06+00:00","first_seen_at":"2026-11-09T22:53:23+00:00","triaged_at":"2026-11-09T22:56:47+00:00","updated_at":"2026-11-09T22:56:47+00:00","category":"ai-tooling","confidence":0.8,"triage":{"at":"2026-11-09T22:56:47Z","model":"claude-haiku-5-5","output":{"fix":"- vLLM: move to `0.31.0` or later.\n- Keep `--trust-request-mm-kwargs` disabled for untrusted clients.","reach":"internet","title":"vLLM: unchecked video frame count lets anyone exhaust server memory","impact":"medium","summary":"vLLM's OpenCV video backend uses a request-supplied num_frames value with no upper limit, so the frame-index allocation grows with whatever a client sends. An unauthenticated request to the chat completions endpoint that selects this backend can exhaust memory and CPU in the API server process until it is killed.","audience":"businesses","category":"ai-tooling","nicknames":[],"who_cares":["vllm","multimodal","self-hosted","openai-compatible-api"],"confidence":0.8,"fix_status":"available","needs_auth":"no","worst_case":"API server runs out of memory and is killed, taking service down","analyst_note":"","how_to_check":"- Check the installed version with `pip show vllm`; versions `>= 0.30.0` and `< 0.31.0` are affected.\n- Check whether the server was launched with `--trust-request-mm-kwargs`; the advisory says to keep it disabled for untrusted clients.\n- Check whether the deployment accepts video input at all, since any video-capable deployment is reachable.","plain_action":"","product_name":"","needs_analyst":false,"not_affected_if":["on-vllm-0.31.0-or-later"],"who_is_affected":"Any vLLM deployment on a version from `0.30.0` up to but not including `0.31.0` that accepts video input is exposed, because the request can select the video backend without any model opting into it. The advisory says no specific model or non-default flag is required, and no authentication is needed. Deployments that are not video-capable, or that are already on `0.31.0` or later, are not covered by this advisory.","user_interaction":"no","product_ecosystem":"","needs_special_setup":"no","severity_if_unknown":"unknown"},"cost_usd":0.001464,"input_tokens":5988,"output_tokens":1731,"severity_before":"medium"},"analyst_status":null,"analyst_note":null,"search":"'+1':288C '-1':298C,441C '-1260':109C,503C '-400':38B '-770':40B '-90':159C,483C '/tokenize':181C '/unconfigured-gpu':167C '/v1/chat/completions':179C '/vllm-project/vllm/pull/58830).':593C '0':227C,254C,310C '0.30.0':511C '0.31.0':512C,517C '1':235C,242C,267C '118':348C '1222':108C,502C '1e7':344C '1e9':353C '42':158C,482C '46':354C '462':345C '51969':381C,455C '58830':385C,519C,590C '63h8':27A,32A '8':315C '894j':25A,30A '9h4c':377C 'add':457C 'advisori':587C 'affect':504C,509C,569C 'aggrav':388C 'ai':35B 'ai-tool':34B 'alloc':72B,314C,399C 'allowlist':478C 'api':45B,98B,329C 'api-serv':328C 'assess':586C 'audit':463C 'auth':208C 'backend':54B,90B,127C,149C,168C,184C,402C,409C,419C,462C,474C,498C,573C 'behavior':552C 'bind':134C 'block':520C 'bound':295C,559C,565C 'branch':302C 'byte':318C 'cap':437C 'capabl':21A,196C 'caus':210C 'ceil':10A,125C 'central':378C,444C 'chat':84B 'choos':289C 'clamp':170C,243C,280C,379C,420C,449C,487C 'class':435C 'class-level':434C 'client':77B,545C 'compat':44B 'complet':85B 'comprehens':322C,398C,585C 'comput':115C 'consid':468C 'control':120C,218C,224C 'cpu':95B,153C,337C,350C 'cwe':37B,39B 'd':311C 'decod':163C 'default':141C,205C,533C 'deploy':22A,197C 'devic':166C 'differ':389C 'disabl':542C 'distinct':394C 'drive':110C 'dtype':259C 'durat':233C,240C,248C,256C,286C 'e.g':425C 'earlier':577C 'element':325C 'enabl':547C 'endpoint':86B 'entir':303C 'everi':324C 'exhaust':13A,92B 'explicit':546C 'exposur':581C 'extrapol':358C 'famili':372C 'fire':245C,281C 'first':513C 'fix':418C,562C,588C 'flag':206C 'float':260C 'fps':220C,226C,234C,241C,249C,271C,287C,297C,440C,491C 'frame':7A,61B,70B,113C,122C,213C,215C,230C,237C,251C,258C,261C,265C,276C,284C,291C,313C,317C,343C,352C,371C,422C,428C,430C,448C,490C 'frame-index':69B,112C 'gate':469C,495C 'gb':355C 'ghsa':24A,29A,374C 'ghsa-894j-wg8m-63h8':23A,28A 'ghsa-vxqj-p4gw-9h4c':373C 'github.com':592C 'github.com/vllm-project/vllm/pull/58830).':591C 'glm/openpangu':199C 'gpu':493C 'gpu-on':492C 'grow':73B 'honor':144C 'host':48B 'hour':356C 'hw':162C 'imag':338C 'in-process':333C 'independ':558C 'index':71B,114C 'indic':262C 'insid':326C 'instanc':365C 'int':231C,238C,285C 'io':530C 'keep':536C 'kill':16A,104B,361C 'knob':175C 'kwarg':156C,452C,485C,527C,531C,541C 'land':445C 'latest':340C 'leav':304C 'level':5A,147C,408C,436C,472C 'limit':66B 'linear':357C 'list':397C 'list-comprehens':396C 'loader':154C 'lower':564C 'mb':346C 'measur':332C 'media':529C 'media_io_kwargs.video.video':148C 'memori':93B 'memory/cpu':12A 'merg':155C,484C 'min':263C,426C 'miss':465C 'mm':525C,540C 'model':137C,200C,413C 'multimod':41B 'non':204C 'non-default':203C 'none':171C 'np.linspace':253C,309C,395C,424C 'num':6A,60B,121C,212C,229C,236C,257C,266C,283C,290C,312C,316C,342C,351C,370C,421C,427C,431C,447C,489C 'offici':336C 'one':176C 'oom':15A,360C 'oom-kil':14A,359C 'openai':43B 'openai-compatible-api':42B 'opencv':52B 'opencvdynamicopenpanguvideobackend':2A,106C 'openpangu':185C 'opt':414C 'origin':270C 'overrid':551C 'p4gw':376C 'packag':506C 'patch':515C 'path':580C 'peak':347C 'per':461C,523C 'per-backend':460C 'per-request':522C 'pool':164C 'post':178C 'pr':380C,454C,518C 'predat':574C 'preprocess':535C 'process':100B,331C,335C 'processor':133C,526C 'processor/sampler':555C 'publish':368C 'pypi':508C 'python':211C,321C 'reach':480C 'reachabl':404C 'record':566C 'regist':129C,152C 'releas':571C,576C 'request':4A,58B,81B,119C,146C,217C,223C,306C,407C,471C,524C,539C,579C 'request-control':118C,216C,222C 'request-level':3A,145C,406C,470C 'request-path':578C 'request-suppli':57B 'requir':201C 'restor':549C 'root':209C 'round':268C 'rout':186C 'sampl':174C,250C,275C 'sampler':191C 'select':88B,138C,410C,475C 'self':47B 'self-host':46B 'send':78B 'server':99B,330C 'sibl':466C 'sink':391C,499C 'size':165C 'skip':300C 'stabl':514C 'static':479C 'stop':464C 'strip':160C 'subsequ':382C 'suggest':417C 'summari':105C 'supersed':383C 'suppli':59B 'target.fps':221C 'target.num':214C 'timestamp':252C,277C 'tool':36B 'total':232C,239C,255C,264C,429C 'treat':439C 'trust':538C,550C 'trust-request-mm-kwarg':537C 'two':387C 'unauthent':11A,80B,177C 'unclamp':219C,369C 'under':554C 'untouch':308C 'untrust':521C,544C 'upper':65B 'use':55B 'v0.30.0':341C,570C 'valu':62B,307C 'verifi':568C 'version':505C,510C,516C 'via':405C 'video':20A,53B,132C,183C,188C,195C,473C,497C 'video-cap':19A,194C 'videomediaio':143C 'videomediaio.merge':451C 'vllm':1A,33A,49B,50B,507C 'vllm/multimodal/media/video.py':157C,481C 'vllm/multimodal/video.py':107C,501C 'vllm/vllm-openai-cpu':339C 'vxqj':375C 'walk':323C 'wg8m':26A,31A 'whatev':75B 'without':8A,130C,411C","nicknames":[],"mitigations":[],"who_affected":"Any vLLM deployment on a version from `0.30.0` up to but not including `0.31.0` that accepts video input is exposed, because the request can select the video backend without any model opting into it. The advisory says no specific model or non-default flag is required, and no authentication is needed. Deployments that are not video-capable, or that are already on `0.31.0` or later, are not covered by this advisory.","tier":"B","verified":{},"analyst_revisit_at":null,"fix_status":"available","audience":"businesses","plain_action":null,"pkeys":["vllm"],"ptokens":["vllm"],"labels":["aitooling","cwe400","cwe770","medium","multimodal","openaicompatibleapi","pypi","selfhosted","vllm"],"campaign_type":null,"search_a":"'63h8':27A,32A '894j':25A,30A 'capabl':21A 'ceil':10A 'deploy':22A 'exhaust':13A 'frame':7A 'ghsa':24A,29A 'ghsa-894j-wg8m-63h8':23A,28A 'kill':16A 'level':5A 'memory/cpu':12A 'num':6A 'oom':15A 'oom-kil':14A 'opencvdynamicopenpanguvideobackend':2A 'request':4A 'request-level':3A 'unauthent':11A 'video':20A 'video-cap':19A 'vllm':1A,33A 'wg8m':26A,31A 'without':8A","search_b":"'-400':38B '-770':40B 'ai':35B 'ai-tool':34B 'alloc':72B 'api':45B,98B 'backend':54B,90B 'chat':84B 'client':77B 'compat':44B 'complet':85B 'cpu':95B 'cwe':37B,39B 'endpoint':86B 'exhaust':92B 'frame':61B,70B 'frame-index':69B 'grow':73B 'host':48B 'index':71B 'kill':104B 'limit':66B 'memori':93B 'multimod':41B 'num':60B 'openai':43B 'openai-compatible-api':42B 'opencv':52B 'process':100B 'request':58B,81B 'request-suppli':57B 'select':88B 'self':47B 'self-host':46B 'send':78B 'server':99B 'suppli':59B 'tool':36B 'unauthent':80B 'upper':65B 'use':55B 'valu':62B 'video':53B 'vllm':49B,50B 'whatev':75B","search_c":"'+1':288C '-1':298C,441C '-1260':109C,503C '-90':159C,483C '/tokenize':181C '/unconfigured-gpu':167C '/v1/chat/completions':179C '/vllm-project/vllm/pull/58830).':593C '0':227C,254C,310C '0.30.0':511C '0.31.0':512C,517C '1':235C,242C,267C '118':348C '1222':108C,502C '1e7':344C '1e9':353C '42':158C,482C '46':354C '462':345C '51969':381C,455C '58830':385C,519C,590C '8':315C '9h4c':377C 'add':457C 'advisori':587C 'affect':504C,509C,569C 'aggrav':388C 'alloc':314C,399C 'allowlist':478C 'api':329C 'api-serv':328C 'assess':586C 'audit':463C 'auth':208C 'backend':127C,149C,168C,184C,402C,409C,419C,462C,474C,498C,573C 'behavior':552C 'bind':134C 'block':520C 'bound':295C,559C,565C 'branch':302C 'byte':318C 'cap':437C 'capabl':196C 'caus':210C 'ceil':125C 'central':378C,444C 'choos':289C 'clamp':170C,243C,280C,379C,420C,449C,487C 'class':435C 'class-level':434C 'client':545C 'comprehens':322C,398C,585C 'comput':115C 'consid':468C 'control':120C,218C,224C 'cpu':153C,337C,350C 'd':311C 'decod':163C 'default':141C,205C,533C 'deploy':197C 'devic':166C 'differ':389C 'disabl':542C 'distinct':394C 'drive':110C 'dtype':259C 'durat':233C,240C,248C,256C,286C 'e.g':425C 'earlier':577C 'element':325C 'enabl':547C 'entir':303C 'everi':324C 'explicit':546C 'exposur':581C 'extrapol':358C 'famili':372C 'fire':245C,281C 'first':513C 'fix':418C,562C,588C 'flag':206C 'float':260C 'fps':220C,226C,234C,241C,249C,271C,287C,297C,440C,491C 'frame':113C,122C,213C,215C,230C,237C,251C,258C,261C,265C,276C,284C,291C,313C,317C,343C,352C,371C,422C,428C,430C,448C,490C 'frame-index':112C 'gate':469C,495C 'gb':355C 'ghsa':374C 'ghsa-vxqj-p4gw-9h4c':373C 'github.com':592C 'github.com/vllm-project/vllm/pull/58830).':591C 'glm/openpangu':199C 'gpu':493C 'gpu-on':492C 'honor':144C 'hour':356C 'hw':162C 'imag':338C 'in-process':333C 'independ':558C 'index':114C 'indic':262C 'insid':326C 'instanc':365C 'int':231C,238C,285C 'io':530C 'keep':536C 'kill':361C 'knob':175C 'kwarg':156C,452C,485C,527C,531C,541C 'land':445C 'latest':340C 'leav':304C 'level':147C,408C,436C,472C 'linear':357C 'list':397C 'list-comprehens':396C 'loader':154C 'lower':564C 'mb':346C 'measur':332C 'media':529C 'media_io_kwargs.video.video':148C 'merg':155C,484C 'min':263C,426C 'miss':465C 'mm':525C,540C 'model':137C,200C,413C 'non':204C 'non-default':203C 'none':171C 'np.linspace':253C,309C,395C,424C 'num':121C,212C,229C,236C,257C,266C,283C,290C,312C,316C,342C,351C,370C,421C,427C,431C,447C,489C 'offici':336C 'one':176C 'oom':360C 'oom-kil':359C 'opencvdynamicopenpanguvideobackend':106C 'openpangu':185C 'opt':414C 'origin':270C 'overrid':551C 'p4gw':376C 'packag':506C 'patch':515C 'path':580C 'peak':347C 'per':461C,523C 'per-backend':460C 'per-request':522C 'pool':164C 'post':178C 'pr':380C,454C,518C 'predat':574C 'preprocess':535C 'process':331C,335C 'processor':133C,526C 'processor/sampler':555C 'publish':368C 'pypi':508C 'python':211C,321C 'reach':480C 'reachabl':404C 'record':566C 'regist':129C,152C 'releas':571C,576C 'request':119C,146C,217C,223C,306C,407C,471C,524C,539C,579C 'request-control':118C,216C,222C 'request-level':145C,406C,470C 'request-path':578C 'requir':201C 'restor':549C 'root':209C 'round':268C 'rout':186C 'sampl':174C,250C,275C 'sampler':191C 'select':138C,410C,475C 'server':330C 'sibl':466C 'sink':391C,499C 'size':165C 'skip':300C 'stabl':514C 'static':479C 'stop':464C 'strip':160C 'subsequ':382C 'suggest':417C 'summari':105C 'supersed':383C 'target.fps':221C 'target.num':214C 'timestamp':252C,277C 'total':232C,239C,255C,264C,429C 'treat':439C 'trust':538C,550C 'trust-request-mm-kwarg':537C 'two':387C 'unauthent':177C 'unclamp':219C,369C 'under':554C 'untouch':308C 'untrust':521C,544C 'v0.30.0':341C,570C 'valu':307C 'verifi':568C 'version':505C,510C,516C 'via':405C 'video':132C,183C,188C,195C,473C,497C 'video-cap':194C 'videomediaio':143C 'videomediaio.merge':451C 'vllm':507C 'vllm/multimodal/media/video.py':157C,481C 'vllm/multimodal/video.py':107C,501C 'vllm/vllm-openai-cpu':339C 'vxqj':375C 'walk':323C 'without':130C,411C","cause_entry":null,"cause_path":null,"disclosures_checked_at":null,"first_public_at":"2026-10-27T22:24:06+00:00","kev":null,"cvss_vector":null,"cvss_by":null,"poc_count":0,"sources":[{"source":"ghsa-repo","external_id":"GHSA-894j-wg8m-63h8","url":"https://github.com/vllm-project/vllm/security/advisories/GHSA-894j-wg8m-63h8","severity":"medium","published_at":"2026-10-27T22:24:06+00:00","modified_at":"2026-10-27T22:24:07+00:00","first_seen_at":"2026-11-09T22:53:23+00:00","fetched_at":"2026-11-09T22:53:23+00:00","note":null}],"documents":[{"id":110582,"url":"https://github.com/vllm-project/vllm/security/advisories/GHSA-894j-wg8m-63h8","title":"Maintainer's advisory: github.com","kind":"vendor","source":"ghsa-repo","publisher":"vendor","text":null,"published_at":null,"relation":"advisory","confidence":null,"note":"Maintainer's advisory: github.com"}],"disclosures":[],"exploit_sources":[],"notice":"Free to read, with fair use of about 60 pages a minute. For higher limits or API access: sales@infrastack.ai"}