Threat Intelligence

Live CVE feed

299 threats tracked across 7 launch stacks — sourced from NVD, GHSA, CISA KEV, OSV, npm Audit, and EPSS.

60threats · AI / LLM Apps · Medium· page 1/3
Get guardrails →

Pydantic AI: SSRF cloud-metadata blocklist bypass via IPv4-mapped IPv6 (Incomplete fix of CVE-2026-25580)

Summary When an application using Pydantic AI opts a URL into force_download='allow-local' (which disables the default block on private/internal IPs), the cloud-metadata blocklist could be bypassed by encoding the metadata IP in an IPv6 transition form (IPv4-mapped IPv6, 6to4, or NAT64). Dual-stack and translated networks route the IPv6 wrapper to the underlying IPv4 endpoint, exposing cloud IAM short-term credentials. This is an incomplete fix of GHSA-2jrp-274c-jhv3 / CVE-2026-25580. The parent advisory's remediation guaranteed that "cloud metadata endpoints are always blocked, even with allow-local." That guarantee did not hold for IPv6-encoded forms of the metadata IPs. Severity Same impact metrics as the parent CVE, but materially narrower attack surface (AC:H instead of AC:L), because exploitation requires the application to have opted into allow-local on a URL influenced by untrusted input. Who Is Affected Applications are affected only if they explicitly opt for FileUrl (ImageUrl, AudioUrl, VideoUrl, DocumentUrl) into force_download='allow-local' on a URL that is, or could be, influenced by untrusted input. Applications are not affected if they use any of the bundled integrations to ingest user input, because they do not propagate force_download from external data: Agent.to_web / clai web VercelAIAdapter AGUIAdapter / Agent.to_ag_ui Applications that only download from developer-controlled URLs are not affected. Remediation Upgrade to 1.99.0 or later. The cloud-metadata and private-IP blocklists now apply to IPv6 transition forms that route to a blocked IPv4 endpoint (IPv4-mapped IPv6, 6to4, and NAT64 well-known prefix). The blocklists have also been extended to cover additional IANA-reserved IPv4 and IPv6 special-purpose ranges. Workaround for Unpatched Versions Avoid passing force_download='allow-local' on any URL that could be influenced by untrusted input. If developers must, resolve the hostname themselves and validate the result against their own metadata blocklist — including IPv6-encoded forms — before constructing the FileUrl. Credits Reported by j0hndo.

OWASP A10LLM02 · Insecure OutputOWASP LLM
Get guardrail →

vLLM: extract_hidden_states speculative decoding crashes server on any request with penalty parameters

Summary The extract_hidden_states speculative decoding proposer in vLLM returns a tensor with an incorrect shape after the first decode step, causing a RuntimeError that crashes the EngineCore process. The crash is triggered when any request in the batch uses sampling penalty parameters (repetition_penalty, frequency_penalty, or presence_penalty). A single request with a penalty parameter (e.g., "repetition_penalty": 1.1) is sufficient to crash the server. The crash is deterministic and immediate — no concurrency, race condition, or special workload is required. Details In vLLM v0.17.0, the extract_hidden_states proposer's propose() method returned sampled_token_ids.unsqueeze(-1), producing a tensor of shape (batch_size, 1). In PR #37013 (first released in v0.18.0), the KV connector interface was refactored out of propose(). The return type changed from tuple[Tensor, KVConnectorOutput | None] to Tensor, and the .unsqueeze(-1) call was removed along with the KV connector output: ``python Before (v0.17.0): return sampled_token_ids.unsqueeze(-1), kv_connector_output # shape (batch_size, 1) After (v0.18.0+): return sampled_token_ids # shape (batch_size, 2) after first decode step ` The refactor missed that sampled_token_ids changed semantics between the first and subsequent decode steps. After the first decode step, the rejection sampler allocates its output as (batch_size, max_spec_len + 1). With num_speculative_tokens=1, this produces shape (batch_size, 2) instead of the expected (batch_size, 1), causing a broadcast shape mismatch during penalty application. Impact Any vLLM deployment between v0.18.0 and v0.19.1 (inclusive) configured with extract_hidden_states speculative decoding is affected. A single API request containing any penalty parameter immediately and permanently crashes the EngineCore process, resulting in complete loss of service availability. Patches Fixed in PR #38610, first included in vLLM v0.20.0. The fix slices the return value to sampled_token_ids[:, :1], ensuring the correct (batch_size, 1) shape regardless of the rejection sampler's output dimensions. Workarounds Upgrade to vLLM v0.20.0 or later. If upgrading is not possible, avoid using extract_hidden_states as the speculative decoding method on affected versions. Alternatively, reject or strip penalty parameters (repetition_penalty, frequency_penalty, presence_penalty`) from incoming requests at an API gateway before they reach vLLM.

vLLM Vulnerable to Remote DoS via Special-Token Placeholders

Summary This report explains a Token Injection vulnerability in vLLM’s multimodal processing. Unauthenticated, text-only prompts that spell special tokens are interpreted as control. Image and video placeholder sequences supplied without matching data cause vLLM to index into empty grids during input-position computation, raising an unhandled IndexError and terminating the worker or degrading availability. Multimodal paths that rely on image_grid_thw/video_grid_thw are affected. Severity: High (remote DoS). Reproduced on vLLM 0.10.0 with Qwen2.5-VL. Details Affected component: multimodal input position computation. File/functions (paths are indicative): vllm/model_executor/layers/rotary_embedding.py get_input_positions_tensor(...) _vl_get_input_positions_tensor(...) Failure mechanism: The code counts detected vision tokens and then indexes video_grid_thw/image_grid_thw accordingly. When user input carries placeholder tokens but no actual multimodal payload, these grids are empty. The code does not bounds-check before indexing. Representative snippet (context): ``python vllm/model_executor/layers/rotary_embedding.py @classmethod def _vl_get_input_positions_tensor( cls, input_tokens, hf_config, image_grid_thw, video_grid_thw, ..., ): # detect video tokens video_nums = (vision_tokens == video_token_id).sum() # later in processing t, h, w = ( video_grid_thw[video_index][0], # IndexError if no video data video_grid_thw[video_index][1], video_grid_thw[video_index][2], ) ` Abbreviated call path: ` OpenAI API request → vllm.v1.engine.core: step/execute_model → vllm.v1.worker.gpu_model_runner: _update_states/execute_model → vllm.model_executor.layers.rotary_embedding: get_input_positions_tensor → _vl_get_input_positions_tensor → IndexError: list index out of range ` PoC Environment vLLM: 0.10.0 Model: Qwen/Qwen2.5-VL-3B-Instruct Launch server: `bash python -m vllm.entrypoints.openai.api_server \ --model Qwen/Qwen2.5-VL-3B-Instruct \ --port 8000 ` Request (text-only, no image/video data) `bash cat > request.json <<'JSON' { "model": "Qwen/Qwen2.5-VL-3B-Instruct", "messages": [ { "role": "user", "content": [ { "type": "text", "text": "what's in picture <|vision_start|><|image_pad|><|vision_end|>" } ] } ] } JSON curl -s http://127.0.0.1:8000/v1/chat/completions \ -H 'Content-Type: application/json' \ --data @request.json `` Observed result HTTP 500; logs show IndexError: list index out of range from _vl_get_input_positions_tensor(...). In some deployments, the worker exits and capacity remains reduced until manual restart. Impact Type: Token Injection leading to Remote Denial of Service (unauthenticated). A single request can trigger the fault. Scope: Any vLLM deployment that serves VLMs and accepts raw user text via OpenAI-compatible endpoints (self-hosted or proxied/managed fronts). Effect: Request → unhandled exception in position computation → worker termination / service unavailability. Fixes Changes associated with https://github.com/vllm-project/vllm/issues/32656 Credits Pengyu Ding (Infra Security, Ant Group) Ziteng Xu (Infra Security, Ant Group)

LangChain has incomplete f-string validation in prompt templates

LangChain's f-string prompt-template validation was incomplete in two respects. First, some prompt template classes accepted f-string templates and formatted them without enforcing the same attribute-access validation as PromptTemplate. In particular, DictPromptTemplate and ImagePromptTemplate could accept templates containing attribute access or indexing expressions and subsequently evaluate those expressions during formatting. Examples of the affected shape include: ``python "{message.additional_kwargs[secret]}" "https://example.com/{image.__class__.__name__}.png" ` Second, f-string validation based on parsed top-level field names did not reject nested replacement fields inside format specifiers. For example: `python "{name:{name.__class__.__name__}}" ` In this pattern, the nested replacement field appears in the format specifier rather than in the top-level field name. As a result, earlier validation based on parsed field names did not reject the template even though Python formatting would still attempt to resolve the nested expression at runtime. Affected usage This issue is only relevant for applications that accept untrusted template strings, rather than only untrusted template variable values. In addition, practical impact depends on what objects are passed into template formatting: If applications only format simple values such as strings and numbers, impact is limited and may only result in formatting errors. If applications format richer Python objects, attribute access and indexing may interact with internal object state during formatting. In many deployments, these conditions are not commonly present together. Applications that allow end users to author arbitrary templates often expose only a narrow set of simple template variables, while applications that work with richer internal Python objects often keep template structure under developer control. As a result, the highest-impact scenario is plausible but is not representative of all LangChain applications. Applications that use hardcoded templates or that only allow users to provide variable values are not affected by this issue. Impact The direct issue in DictPromptTemplate and ImagePromptTemplate allowed attribute access and indexing expressions to survive template construction and then be evaluated during formatting. When richer Python objects were passed into formatting, this could expose internal fields or nested data to prompt output, model context, or logs. The nested format-spec issue is narrower in scope. It bypassed the intended validation rules for f-string templates, but in simple cases it results in an invalid format specifier error rather than direct disclosure. Accordingly, its practical impact is lower than that of direct top-level attribute traversal. Overall, the practical severity depends on deployment. Meaningful confidentiality impact requires attacker control over the template structure itself, and higher impact further depends on the surrounding application passing richer internal Python objects into formatting. Fix The fix consists of two changes. First, LangChain now applies f-string safety validation consistently to DictPromptTemplate and ImagePromptTemplate, so templates containing attribute access or indexing expressions are rejected during construction and deserialization. Second, LangChain now rejects nested replacement fields inside f-string format specifiers. Concretely, LangChain validates parsed f-string fields and raises an error for: variable names containing attribute access or indexing syntax such as . or [] format specifiers containing { or } This blocks templates such as: `python "{message.additional_kwargs[secret]}" "https://example.com/{image.__class__.__name__}.png" "{name:{name.__class__.__name__}}" ` The fix preserves ordinary f-string formatting features such as standard format specifiers and conversions, including examples like: `python "{value:.2f}" "{value:>10}" "{value!r}" `` In addition, the explicit template-validation path now applies the same structural f-string checks before performing placeholder validation, ensuring that the security checks and validation checks remain aligned.

OWASP A03LLM01 · Prompt InjectionOWASP LLM
Get guardrail →
2 rules

HuggingFace Transformers allows for arbitrary code execution in the `Trainer` class

A vulnerability in the HuggingFace Transformers library, specifically in the Trainer class, allows for arbitrary code execution. The _load_rng_state() method in src/transformers/trainer.py at line 3059 calls torch.load() without the weights_only=True parameter. This issue affects all versions of the library supporting torch>=2.2 when used with PyTorch versions below 2.6, as the safe_globals() context manager provides no protection in these versions. An attacker can exploit this vulnerability by supplying a malicious checkpoint file, such as rng_state.pth, which can execute arbitrary code when loaded. The issue is resolved in version v5.0.0rc3.

OWASP A08LLM05 · Supply ChainOWASP LLM
Get guardrail →

vLLM: Denial of Service via Unbounded Frame Count in video/jpeg Base64 Processing

Summary The VideoMediaIO.load_base64() method at vllm/multimodal/media/video.py:51-62 splits video/jpeg data URLs by comma to extract individual JPEG frames, but does not enforce a frame count limit. The num_frames parameter (default: 32), which is enforced by the load_bytes() code path at line 47-48, is completely bypassed in the video/jpeg base64 path. An attacker can send a single API request containing thousands of comma-separated base64-encoded JPEG frames, causing the server to decode all frames into memory and crash with OOM. Details Vulnerable code ``python video.py:51-62 def load_base64(self, media_type: str, data: str) -> tuple[npt.NDArray, dict[str, Any]]: if media_type.lower() == "video/jpeg": load_frame = partial(self.image_io.load_base64, "image/jpeg") return np.stack( [np.asarray(load_frame(frame_data)) for frame_data in data.split(",")] # ^^^^^^^^^^ # Unbounded split — no frame count limit ), {} return self.load_bytes(base64.b64decode(data)) ` The load_bytes() path (line 47-48) properly delegates to a video loader that respects self.num_frames (default 32). The load_base64("video/jpeg", ...) path bypasses this limit entirely — data.split(",") produces an unbounded list and every frame is decoded into a numpy array. video/jpeg is part of vLLM's public API video/jpeg is a vLLM-specific MIME type, not IANA-registered. However it is part of the public API surface: encode_video_url() at vllm/multimodal/utils.py:96-108 generates data:video/jpeg;base64,... URLs Official test suites at tests/entrypoints/openai/test_video.py:62 and tests/entrypoints/test_chat_utils.py:153 both use this format Memory amplification Each JPEG frame decodes to a full numpy array. For 640x480 RGB images, each frame is ~921 KB decoded. 5000 frames = ~4.6 GB. np.stack() then creates an additional copy. The compressed JPEG payload is small (~100 KB for 5000 frames) but decompresses to gigabytes. Data flow ` POST /v1/chat/completions → chat_utils.py:1434 video_url type → mm_parser.parse_video() → chat_utils.py:872 parse_video() → self._connector.fetch_video() → connector.py:295 fetch_video() → load_from_url(url, self.video_io) → connector.py:91 _load_data_url(): url_spec.path.split(",", 1) → media_type = "video/jpeg" → data = "<frame1>,<frame2>,...,<frame10000>" → connector.py:100 media_io.load_base64("video/jpeg", data) → video.py:54 data.split(",") ← UNBOUNDED → video.py:55-57 all frames decoded into numpy arrays → video.py:56 np.stack([...]) ← massive combined array → OOM ` connector.py:91 uses split(",", 1) which splits on only the first comma. All remaining commas stay in data and are later split by video.py:54. Comparison with existing protections | Code Path | Frame Limit | File | |-----------|-------------|------| | load_bytes() (binary video) | Yes — num_frames (default 32) | video.py:46-49 | | load_base64("video/jpeg", ...) | No — unlimited data.split(",")` | video.py:51-62 |

vLLM: Server-Side Request Forgery (SSRF) in `download_bytes_from_url `

Summary A Server Side Request Forgery (SSRF) vulnerability in download_bytes_from_url allows any actor who can control batch input JSON to make the vLLM batch runner issue arbitrary HTTP/HTTPS requests from the server, without any URL validation or domain restrictions. This can be used to target internal services (e.g. cloud metadata endpoints or internal HTTP APIs) reachable from the vLLM host. ------ Details Vulnerable component The vulnerable logic is in the batch runner entrypoint vllm/entrypoints/openai/run_batch.py, function download_bytes_from_url: `` run_batch.py Lines 442-482 async def download_bytes_from_url(url: str) -> bytes: """ Download data from a URL or decode from a data URL. Args: url: Either an HTTP/HTTPS URL or a data URL (data:...;base64,...) Returns: Data as bytes """ parsed = urlparse(url) # Handle data URLs (base64 encoded) if parsed.scheme == "data": # Format: data:...;base64,<base64_data> if "," in url: header, data = url.split(",", 1) if "base64" in header: return base64.b64decode(data) else: raise ValueError(f"Unsupported data URL encoding: {header}") else: raise ValueError(f"Invalid data URL format: {url}") # Handle HTTP/HTTPS URLs elif parsed.scheme in ("http", "https"): async with ( aiohttp.ClientSession() as session, session.get(url) as resp, ): if resp.status != 200: raise Exception( f"Failed to download data from URL: {url}. Status: {resp.status}" ) return await resp.read() else: raise ValueError( f"Unsupported URL scheme: {parsed.scheme}. " "Supported schemes: http, https, data" ) ` Key properties: The function only parses the URL to dispatch on the scheme (data, http, https). For http / https, it directly calls session.get(url) on the provided string. There is no validation of: hostname or IP address, whether the target is internal or external, port number, path, query, or redirect target. This is in contrast to the multimodal media path (MediaConnector), which implements an explicit domain allowlist. download_bytes_from_url does not reuse that protection. URL controllability The url argument is fully controlled by batch input JSON via the file_url field of BatchTranscriptionRequest / BatchTranslationRequest. 1. Batch request body type: ` run_batch.py Line 67-80 class BatchTranscriptionRequest(TranscriptionRequest): """ Batch transcription request that uses file_url instead of file. This class extends TranscriptionRequest but replaces the file field with file_url to support batch processing from audio files written in JSON format. """ file_url: str = Field( ..., description=( "Either a URL of the audio or a data URL with base64 encoded audio data. " ), ) ` ` run_batch.py Line 98-111 class BatchTranslationRequest(TranslationRequest): """ Batch translation request that uses file_url instead of file. This class extends TranslationRequest but replaces the file field with file_url to support batch processing from audio files written in JSON format. """ file_url: str = Field( ..., description=( "Either a URL of the audio or a data URL with base64 encoded audio data. " ), ) ` There is no restriction on the domain, IP, or port of file_url in these models. 1. Batch input is parsed directly from the batch file: ` run_batch.py Line 139-179 class BatchRequestInput(OpenAIBaseModel): ... url: str body: BatchRequestInputBody @field_validator("body", mode="plain") @classmethod def check_type_for_url(cls, value: Any, info: ValidationInfo): url: str = info.data["url"] ... if url == "/v1/audio/transcriptions": return BatchTranscriptionRequest.model_validate(value) if url == "/v1/audio/translations": return BatchTranslationRequest.model_validate(value) ` ` run_batch.py Line 770-781 logger.info("Reading batch from %s...", args.input_file) # Submit all requests in the file to the engine "concurrently". response_futures: list[Awaitable[BatchRequestOutput]] = [] for request_json in (await read_file(args.input_file)).strip().split("\n"): # Skip empty lines. request_json = request_json.strip() if not request_json: continue request = BatchRequestInput.model_validate_json(request_json) ` The batch runner reads each line of the input file (args.input_file), parses it as JSON, and constructs a BatchTranscriptionRequest / BatchTranslationRequest. Whatever file_url appears in that JSON line becomes batch_request_body.file_url. 1. file_url is passed directly into download_bytes_from_url: ` run_batch.py Line 610-623 def wrapper(handler_fn: Callable): async def transcription_wrapper( batch_request_body: (BatchTranscriptionRequest | BatchTranslationRequest), ) -> ( TranscriptionResponse | TranscriptionResponseVerbose | TranslationResponse | TranslationResponseVerbose | ErrorResponse ): try: # Download data from URL audio_data = await download_bytes_from_url(batch_request_body.file_url) ` So the data flow is: 1. Attacker supplies JSON line in the batch input file with arbitrary body.file_url. 2. BatchRequestInput / BatchTranscriptionRequest / BatchTranslationRequest parse that JSON and store file_url verbatim. 3. make_transcription_wrapper calls download_bytes_from_url(batch_request_body.file_url). 4. download_bytes_from_url’s HTTP/HTTPS branch issues aiohttp.ClientSession().get(url) to that attacker-controlled URL with no further validation. This is a classic SSRF pattern: a server-side component makes arbitrary HTTP requests to a URL string taken from untrusted input. Comparison with safer code The project already contains a safer URL-handling path for multimodal media in vllm/multimodal/media/connector.py, which demonstrates the intent to mitigate SSRF via domain allowlists and URL normalization: ` connector.py Lines 169-189 def load_from_url( self, url: str, media_io: MediaIO[_M], *, fetch_timeout: int | None = None, ) -> _M: # type: ignore[type-var] url_spec = parse_url(url) if url_spec.scheme and url_spec.scheme.startswith("http"): self._assert_url_in_allowed_media_domains(url_spec) connection = self.connection data = connection.get_bytes( url_spec.url, timeout=fetch_timeout, allow_redirects=envs.VLLM_MEDIA_URL_ALLOW_REDIRECTS, ) return media_io.load_bytes(data) ` and: ` connector.py Lines 158-167 def _assert_url_in_allowed_media_domains(self, url_spec: Url) -> None: if ( self.allowed_media_domains and url_spec.hostname not in self.allowed_media_domains ): raise ValueError( f"The URL must be from one of the allowed domains: " f"{self.allowed_media_domains}. Input URL domain: " f"{url_spec.hostname}" ) ` download_bytes_from_url` does not reuse this allowlist or any equivalent validation, even though it also fetches user-provided URLs.

OWASP A10LLM02 · Insecure OutputOWASP LLM
Get guardrail →

vLLM: Unauthenticated OOM Denial of Service via Unbounded `n` Parameter in OpenAI API Server

Summary A Denial of Service vulnerability exists in the vLLM OpenAI-compatible API server. Due to the lack of an upper bound validation on the n parameter in the ChatCompletionRequest and CompletionRequest Pydantic models, an unauthenticated attacker can send a single HTTP request with an astronomically large n value. This completely blocks the Python asyncio event loop and causes immediate Out-Of-Memory crashes by allocating millions of request object copies in the heap before the request even reaches the scheduling queue. Details The root cause of this vulnerability lies in the missing upper bound checks across the request parsing and asynchronous scheduling layers: 1. Protocol Layer: In vllm/entrypoints/openai/chat_completion/protocol.py, the n parameter is defined simply as an integer without any pydantic.Field constraints for an upper bound. ``python class ChatCompletionRequest(OpenAIBaseModel): # Ordered by official OpenAI API documentation # https://platform.openai.com/docs/api/reference/chat/create messages: list[ChatCompletionMessageParam] model: str | None = None frequency_penalty: float | None = 0.0 logit_bias: dict[str, float] | None = None logprobs: bool | None = False top_logprobs: int | None = 0 max_tokens: int | None = Field( default=None, deprecated="max_tokens is deprecated in favor of " "the max_completion_tokens field", ) max_completion_tokens: int | None = None n: int | None = 1 presence_penalty: float | None = 0.0 ` 1. SamplingParams Layer (Incomplete Validation): When the API request is converted to internal SamplingParams in vllm/sampling_params.py, the _verify_args method only checks the lower bound (self.n < 1), entirely omitting an upper bounds check. `python def _verify_args(self) -> None: if not isinstance(self.n, int): raise ValueError(f"n must be an int, but is of type {type(self.n)}") if self.n < 1: raise ValueError(f"n must be at least 1, got {self.n}.") ` 1. Engine Layer (The OOM Trigger): When the malicious request reaches the core engine (vllm/v1/engine/async_llm.py), the engine attempts to fan out the request n times to generate identical independent sequences within a synchronous loop. `python # Fan out child requests (for n>1). parent_request = ParentRequest(request) for idx in range(parent_params.n): request_id, child_params = parent_request.get_child_info(idx) child_request = request if idx == parent_params.n - 1 else copy(request) child_request.request_id = request_id child_request.sampling_params = child_params await self._add_request( child_request, prompt_text, parent_request, idx, queue ) return queue ` Because Python's asyncio runs on a single thread and event loop, this monolithic for-loop monopolizes the CPU thread. The server stops responding to all other connections (including liveness probes). Simultaneously, the memory allocator is overwhelmed by cloning millions of request object instances via copy(request), driving the host's Resident Set Size (RSS) up by gigabytes per second until the OS OOM-killer terminates the vLLM process. Impact Vulnerability Type: Resource Exhaustion / Denial of Service Impacted Parties: Any individual or organization hosting a public-facing vLLM API server (vllm.entrypoints.openai.api_server`), which happens to be the primary entrypoint for OpenAI-compatible setups. SaaS / AI-as-a-Service platforms acting as reverse proxies sitting in front of vLLM without strict HTTP body payload validation or rate limitations. Because this vulnerability exploits the control plane rather than the data plane, an unauthenticated remote attacker can achieve a high success rate in taking down production inference hosts with a single HTTP request. This effectively circumvents any hardware-level capacity planning and conventional bandwidth stress limitations.

Claude SDK for Python: Memory Tool Path Validation Race Condition Allows Sandbox Escape

The async local filesystem memory tool in the Anthropic Python SDK validated that model-supplied paths resolved inside the sandboxed memory directory, but then returned the unresolved path for subsequent file operations. A local attacker able to write to the memory directory could retarget a symlink between validation and use, causing reads or writes to escape the sandbox. The synchronous memory tool implementation was not affected. Users on the affected versions are advised to update to the latest version. Claude SDK for Python thanks hackerone.com/kasthelord for reporting this issue!

OWASP A01OWASP LLM
Get guardrail →

Claude SDK for Python has Insecure Default File Permissions in Local Filesystem Memory Tool

The local filesystem memory tool in the Anthropic Python SDK created memory files with mode 0o666, leaving them world-readable on systems with a standard umask and world-writable in environments with a permissive umask such as many Docker base images. A local attacker on a shared host could read persisted agent state, and in containerized deployments could modify memory files to influence subsequent model behavior. Both the synchronous and asynchronous memory tool implementations were affected. Users on the affected versions are advised to update to the latest version. Claude SDK for Python thanks lucasfutures on HackerOne for the report.

OWASP A05OWASP LLM
Get guardrail →

vLLM has SSRF Protection Bypass

Summary The SSRF protection fix for https://github.com/vllm-project/vllm/security/advisories/GHSA-qh4c-xf7m-gxfc can be bypassed in the load_from_url_async method due to inconsistent URL parsing behavior between the validation layer and the actual HTTP client. Affected Component File: vllm/connections.py Function: load_from_url_async Vulnerability Details Root Cause The SSRF fix uses urllib3.util.parse_url() to validate and extract the hostname from user-provided URLs. However, load_from_url_async uses aiohttp for making the actual HTTP requests, and aiohttp internally uses the yarl library for URL parsing. These two URL parsers handle backslash characters (\) differently: | Parser | Input URL | Parsed Host | Parsed Path | Behavior | |--------|-----------|-------------|-------------|----------| | urllib3.parse_url() | https://httpbin.org\@evil.com/ | httpbin.org | /%5C@evil.com/ | URL-encodes \ as %5C, treats \@evil.com/ as part of the path | | yarl (via aiohttp) | https://httpbin.org\@evil.com/ | evil.com | / | Treats \ as part of userinfo (user: httpbin.org\), the @ acts as the userinfo/host separator | Attack Scenario ``python Attacker provides this URL malicious_url = "https://httpbin.org\\@evil.com/" 1. Validation layer (urllib3.parse_url) parsed = urllib3.util.parse_url(malicious_url) parsed.host == "httpbin.org" ✅ Passes validation 2. Actual request (aiohttp with yarl) async with aiohttp.ClientSession() as session: async with session.get(malicious_url) as response: # Request actually goes to evil.com! ❌ Bypass! ` Why This Happens 1. yarl: Interprets httpbin.org\ as the userinfo component, and @ as the userinfo/host separator, so the URL is parsed as user=httpbin.org\, host=evil.com, path=/ 2. urllib3: URL-encodes the backslash as %5C, so \@evil.com/ becomes /%5C@evil.com/ which is treated as part of the path, leaving host=httpbin.org` This inconsistency allows an attacker to: Bypass the hostname allowlist check Access arbitrary internal/external services Perform full SSRF attacks Fixes https://github.com/vllm-project/vllm/pull/34743

OWASP A10LLM02 · Insecure OutputOWASP LLM
Get guardrail →

Gradio has an Open Redirect in its OAuth Flow

Summary The _redirect_to_target() function in Gradio's OAuth flow accepts an unvalidated _target_url query parameter, allowing redirection to arbitrary external URLs. This affects the /logout and /login/callback endpoints on Gradio apps with OAuth enabled (i.e. apps running on Hugging Face Spaces with gr.LoginButton). Details ``python def _redirect_to_target(request, default_target="/"): target = request.query_params.get("_target_url", default_target) return RedirectResponse(target) # No validation `` An attacker can craft a URL like https://my-space.hf.space/logout?_target_url=https://evil.com/phishing that redirects the user to an external site after logout. Because the URL originates from a trusted hf.space domain, users are more likely to trust the link. Impact Phishing — an attacker can use the trusted domain to redirect users to a malicious site. No direct data exposure or server-side impact. ## Fix The _target_url parameter is now sanitized to only use the path, query, and fragment, stripping any scheme or host.

OWASP A01OWASP A02LLM02 · Insecure OutputLLM06 · Sensitive Info Disclosure
Get guardrail →
2 rules

llama-index-core vulnerable to Uncontrolled Resource Consumption

The SimpleDirectoryReader component in llama_index.core version 0.12.23 suffers from uncontrolled memory consumption due to a resource management flaw. The vulnerability arises because the user-specified file limit (num_files_limit) is applied after all files in a directory are loaded into memory. This can lead to memory exhaustion and degraded performance, particularly in environments with limited resources. The issue is resolved in version 0.12.41.

OWASP A06LLM04 · Model DoSOWASP LLM
Get guardrail →

vLLM is vulnerable to DoS in Idefics3 vision models via image payload with ambiguous dimensions

Summary Users can crash the vLLM engine serving multimodal models that use the _Idefics3_ vision model implementation by sending a specially crafted 1x1 pixel image. This causes a tensor dimension mismatch that results in an unhandled runtime error, leading to complete server termination. Details The vulnerability is triggered when the image processor encounters a 1x1 pixel image with shape (1, 1, 3) in HWC (Height, Width, Channel) format. Due to the ambiguous dimensions, the processor incorrectly assumes the image is in CHW (Channel, Height, Width) format with shape (3, H, W). This misinterpretation causes an incorrect calculation of the number of image patches, resulting in a fatal tensor split operation failure. Crash location: vllm/model_executor/models/idefics3.py line 672: ``python def _process_image_input(self, image_input: ImageInputs) -> torch.Tensor | list[torch.Tensor]: # ... num_patches = image_input["num_patches"] return [e.flatten(0, 1) for e in image_features.split(num_patches.tolist())] ` The split() call fails because the computed num_patches value (17) does not match the actual tensor dimension (9): ` RuntimeError: split_with_sizes expects split_sizes to sum exactly to 9 (input tensor's size at dimension 0), but got split_sizes=[17] ` This unhandled exception terminates the EngineCore process, crashing the server. Affected Models Any model using the Idefics3 architecture. The vulnerability was tested with HuggingFaceTB/SmolVLM-Instruct. Impact Denial of service by crashing the engine Mitigation Validating the input: `python def _validate_image_dimensions(self, image_shape): h, w = image_shape[:2] if len(image_shape) == 3 else image_shape if h < MIN_IMAGE_SIZE or w < MIN_IMAGE_SIZE: raise ValueError(f"Image dimensions too small: {h}x{w}") ` Managing the exception: `python try: return [e.flatten(0, 1) for e in image_features.split(num_patches.tolist())] except RuntimeError as e: logger.error(f"Image processing failed: {e}") raise InvalidImageError("Failed to process image features") from e `` Fixes https://github.com/vllm-project/vllm/pull/29881

vLLM vulnerable to DoS via large Chat Completion or Tokenization requests with specially crafted `chat_template_kwargs`

Summary The /v1/chat/completions and /tokenize endpoints allow a chat_template_kwargs request parameter that is used in the code before it is properly validated against the chat template. With the right chat_template_kwargs parameters, it is possible to block processing of the API server for long periods of time, delaying all other requests Details In serving_engine.py, the chat_template_kwargs are unpacked into kwargs passed to chat_utils.py apply_hf_chat_template with no validation on the keys or values in that chat_template_kwargs dict. This means they can be used to override optional parameters in the apply_hf_chat_template method, such as tokenize, changing its default from False to True. https://github.com/vllm-project/vllm/blob/2a6dc67eb520ddb9c4138d8b35ed6fe6226997fb/vllm/entrypoints/openai/serving_engine.py#L809-L814 https://github.com/vllm-project/vllm/blob/2a6dc67eb520ddb9c4138d8b35ed6fe6226997fb/vllm/entrypoints/chat_utils.py#L1602-L1610 Both serving_chat.py and serving_tokenization.py call into this _preprocess_chat method of serving_engine.py and they both pass in chat_template_kwargs. So, a chat_template_kwargs like {"tokenize": True} makes tokenization happen as part of applying the chat template, even though that is not expected. Tokenization is a blocking operation, and with sufficiently large input can block the API server's event loop, which blocks handling of all other requests until this tokenization is complete. This optional tokenize parameter to apply_hf_chat_template does not appear to be used, so one option would be to just hard-code that to always be False instead of allowing it to be optionally overridden by callers. A better option may be to not pass chat_template_kwargs as unpacked kwargs but instead as a dict, and only unpack them after the logic in apply_hf_chat_template that resolves the kwargs against the chat template. Impact Any authenticated user can cause a denial of service to a vLLM server with Chat Completion or Tokenize requests. Fix https://github.com/vllm-project/vllm/pull/27205

vLLM vulnerable to DoS with incorrect shape of multimodal embedding inputs

Summary Users can crash the vLLM engine serving multimodal models by passing multimodal embedding inputs with correct ndim but incorrect shape (e.g. hidden dimension is wrong), regardless of whether the model is intended to support such inputs (as defined in the Supported Models page). The issue has existed ever since we added support for image embedding inputs, i.e. #6613 (released in v0.5.5) Details Using image embeddings as an example: For models that support image embedding inputs, the engine crashes when scattering the embeddings to inputs_embeds (mismatched shape) For models that don't support image embedding inputs, the engine crashes when validating the inputs inside get_input_embeddings (validation fails). This happens because we only validate ndim of the tensor, but not the full shape, in input processor (via MultiModalDataParser). Impact Denial of service by crashing the engine Mitigation Use API key to limit access to trusted users. Set --limit-mm-per-prompt to 0 for all non-text modalities to ban multimodal inputs, which includes multimodal embedding inputs. However, the model would then only accept text, defeating the purpose of using a multi-modal model. Resolution https://github.com/vllm-project/vllm/pull/27204

vLLM: Resource-Exhaustion (DoS) through Malicious Jinja Template in OpenAI-Compatible Server

Summary A resource-exhaustion (denial-of-service) vulnerability exists in multiple endpoints of the OpenAI-Compatible Server due to the ability to specify Jinja templates via the chat_template and chat_template_kwargs parameters. If an attacker can supply these parameters to the API, they can cause a service outage by exhausting CPU and/or memory resources. Details When using an LLM as a chat model, the conversation history must be rendered into a text input for the model. In hf/transformer, this rendering is performed using a Jinja template. The OpenAI-Compatible Server launched by vllm serve exposes a chat_template parameter that lets users specify that template. In addition, the server accepts a chat_template_kwargs parameter to pass extra keyword arguments to the rendering function. Because Jinja templates support programming-language-like constructs (loops, nested iterations, etc.), a crafted template can consume extremely large amounts of CPU and memory and thereby trigger a denial-of-service condition. Importantly, simply forbidding the chat_template parameter does not fully mitigate the issue. The implementation constructs a dictionary of keyword arguments for apply_hf_chat_template and then updates that dictionary with the user-supplied chat_template_kwargs via dict.update. Since dict.update can overwrite existing keys, an attacker can place a chat_template key inside chat_template_kwargs to replace the template that will be used by apply_hf_chat_template. ``python vllm/entrypoints/openai/serving_engine.py#L794-L816 _chat_template_kwargs: dict[str, Any] = dict( chat_template=chat_template, add_generation_prompt=add_generation_prompt, continue_final_message=continue_final_message, tools=tool_dicts, documents=documents, ) _chat_template_kwargs.update(chat_template_kwargs or {}) request_prompt: Union[str, list[int]] if isinstance(tokenizer, MistralTokenizer): ... else: request_prompt = apply_hf_chat_template( tokenizer=tokenizer, conversation=conversation, model_config=model_config, *_chat_template_kwargs, ) ` Impact If an OpenAI-Compatible Server exposes endpoints that accept chat_template or chat_template_kwargs from untrusted clients, an attacker can submit a malicious Jinja template (directly or by overriding chat_template inside chat_template_kwargs`) that consumes excessive CPU and/or memory. This can result in a resource-exhaustion denial-of-service that renders the server unresponsive to legitimate requests. Fixes https://github.com/vllm-project/vllm/pull/25794

OWASP A03OWASP A06LLM01 · Prompt InjectionLLM04 · Model DoS
Get guardrail →
2 rules

Hugging Face Transformers vulnerable to Regular Expression Denial of Service (ReDoS) in the AdamWeightDecay optimizer

The huggingface/transformers library, versions prior to 4.53.0, is vulnerable to Regular Expression Denial of Service (ReDoS) in the AdamWeightDecay optimizer. The vulnerability arises from the _do_use_weight_decay method, which processes user-controlled regular expressions in the include_in_weight_decay and exclude_from_weight_decay lists. Malicious regular expressions can cause catastrophic backtracking during the re.search call, leading to 100% CPU utilization and a denial of service. This issue can be exploited by attackers who can control the patterns in these lists, potentially causing the machine learning task to hang and rendering services unresponsive.

OWASP A06LLM04 · Model DoSOWASP LLM
Get guardrail →
2 rules

Hugging Face Transformers library has Regular Expression Denial of Service

A Regular Expression Denial of Service (ReDoS) vulnerability was discovered in the Hugging Face Transformers library, specifically within the normalize_numbers() method of the EnglishNormalizer class. This vulnerability affects versions up to 4.52.4 and is fixed in version 4.53.0. The issue arises from the method's handling of numeric strings, which can be exploited using crafted input strings containing long sequences of digits, leading to excessive CPU consumption. This vulnerability impacts text-to-speech and number normalization tasks, potentially causing service disruption, resource exhaustion, and API vulnerabilities.

2 rules

Hugging Face Transformers Regular Expression Denial of Service (ReDoS) vulnerability

A Regular Expression Denial of Service (ReDoS) vulnerability exists in the Hugging Face Transformers library, specifically in the convert_tf_weight_name_to_pt_weight_name() function. This function, responsible for converting TensorFlow weight names to PyTorch format, uses a regex pattern /[^/]___([^/])/ that can be exploited to cause excessive CPU consumption through crafted input strings due to catastrophic backtracking. The vulnerability affects versions up to 4.51.3 and is fixed in version 4.53.0. This issue can lead to service disruption, resource exhaustion, and potential API service vulnerabilities, impacting model conversion processes between TensorFlow and PyTorch formats.

Showing 120 of 60 threats