Wysoka

9router: Image prefetch DNS rebinding allows SSRF to internal services

  • Ujawniono: 23.09.2026
  • Aktualizacja: 11.10.2026 10:22

Summary

9router validates image URLs by resolving the host before fetching, but the later server-side fetch performs a separate DNS resolution. An attacker-controlled DNS name can resolve to a public IP during validation and then rebind to an internal Docker/private IP during the fetch. This allows the server-side image prefetch to reach internal-only HTTP services (SSRF).

Details

  • Affected version / commit: 9router v0.4.80 @ b282f05.
  • Reachable through /v1/chat/completions with a vision-capable model and an image_url content part. A vision-capable model name is required so the image survives modality stripping and the server-side prefetch is armed.
  • The provider used in this reproduction is the bundled mock provider — no real API key and no real provider call.
  • internal-admin (the SSRF target) is not exposed to the host network; it is reachable only from inside the Docker network.
  • rebind-dns behaviour for rebind.9r.test:
    • first A response → 1.1.1.1 (public) to pass the public-host guard,
    • second A response → 172.29.0.10 (internal-admin) during the fetch.
  • internal-admin logs GET /ssrf-marker with peer=172.29.0.30 (the proxied-router container), proving the server-side fetch landed on the internal service.
  • mock-provider receives POST /api/chat and the flow completes with HTTP 200.
  • Root cause: DNS TOCTOU — the IP is not pinned between the validation resolution (the public-host guard) and the fetch resolution. The guard and the fetch each resolve the hostname independently, so a TTL-0 rebinding authority can return a public IP to the guard and an internal IP to the fetch.

Proof of Concept

This repository is a self-contained Docker Compose reproduction. No real provider is called and no real API key is required.

  1. Build and start the stack:
    bash
    docker compose up --build
  2. Confirm internal-admin is unreachable from the host:
    bash
    curl -i http://127.0.0.1:18083/ssrf-marker   # connection refused / fail
    docker compose ps                            # internal-admin has NO host port mapping
  3. Send the request named POST image-prefetch DNS rebinding trigger from requests.http, or with curl:
    bash
    curl -i -X POST http://127.0.0.1:18082/v1/chat/completions \
      -H "Content-Type: application/json" \
      -d '{
        "model": "ollama-local/gemma3",
        "messages": [{"role":"user","content":[
          {"type":"text","text":"reproduction image-prefetch trigger"},
          {"type":"image_url","image_url":{"url":"http://rebind.9r.test:8080/ssrf-marker?case=rebind-trigger"}}
        ]}],
        "stream": false
      }'

Impact

  • SSRF to internal HTTP services reachable from the 9router host/container.
  • Depending on the environment, this can reach cloud metadata endpoints, internal admin panels, or be used for internal service discovery.
  • Blind / semi-blind SSRF when the fetched response is not returned to the attacker; an exfil variant (pointing the image at an internal endpoint that returns valid image bytes) can return internal content base64-encoded to the upstream.
  • Requires a code path that prefetches/normalizes remote images for vision-capable providers.
  • No real credential is needed for the reproduction.

Suggested Fix

  • Pin the resolved IP after validation and connect to that IP (resolve once, then reuse the address for the fetch).
  • Block private, loopback, link-local, multicast, and cloud-metadata ranges at connect time, not only at validation time.
  • Perform DNS resolution and IP checks immediately before the request and against the address actually used to connect.
  • Disable redirects, or re-validate every redirect target with the same checks.
  • Enforce an allowlist for image-fetch domains where feasible.
  • Add a timeout, a response size limit, and a content-type check.

Czego dotyczy

Kliknij technologię, aby zobaczyć wszystkie dotyczące jej podatności.

PlatformaPaczkaPodatne wersjePoprawka w wersji
Paczka npm 9router < 0.5.2 0.5.2

Odnośniki

Ocena CVSS 7.4/10
Wektor CVSS
CVSS:3.1/AV:N/AC:L/PR:L/UI:N/S:C/C:L/I:L/A:L
Słabość (CWE)
CWE-367, CWE-918
Platforma
npm
Paczka
9router
Ujawniono
23.09.2026
Aktualizacja
11.10.2026 10:22

Źródła i licencje

OSV / GitHub Advisory Database - GHSA-cmhj-wh2f-9cgx - CC BY 4.0

Historia podatności: 9router

Wszystkie opisane podatności tej paczki (Paczka npm), od najnowszej. Widać, czy to jednorazowa wpadka, czy paczka, której trzeba pilnować.

Wszystkie (17) w archiwum
Wszystkich wpisów
17
Pierwsza → ostatnia
04.2026 09.2026
Bez poprawki
4
Wykorzystywana w atakach
0

Rozkład istotności

  • Krytyczna 5
  • Wysoka 9
  • Średnia 3

Ujawnienia w latach

  1. 2026: 17
Istotność:
  1. 9router: Image prefetch DNS rebinding allows SSRF to internal services ten wpis
    Wysoka · 7.4 CVE-2026-56676 < 0.5.2 0.5.2
  2. Krytyczna · 9.8 CVE-2026-49352 >= 0.2.21, < 0.4.45 0.4.45
  3. Krytyczna CVE-2026-59800 < 0.4.44 0.4.44
  4. Krytyczna · 10.0 CVE-2026-46339 >= 0.4.30, < 0.4.37 0.4.37

Dowiedz się, które podatności dotyczą Twojej aplikacji

Po podłączeniu integracji DockRay i włączeniu raportowania oprogramowania DockRay porównuje zgłoszone wersje komponentów ze znanymi podatnościami i powiadamia o potwierdzonych dopasowaniach. Zakres zależy od obsługiwanej technologii i dostępnych biuletynów.

Podłącz swoją aplikację
Newsletter DockRay

Bezpieczeństwo aplikacji w Twojej skrzynce

Najważniejsze podatności, konkretne zalecenia i praktyczne wskazówki dla Twoich aplikacji. Wybierz technologie i śledź to, co ma znaczenie dla Twojego projektu.

  • Codzienne zestawienie nowych podatności, także krytycznych.
  • Powiadomienia o ważnych aktualizacjach.
  • Praktyczne porady o bezpieczeństwie i monitoringu aplikacji.

Pozostaw puste, aby otrzymywać informacje o wszystkich technologiach.

Zapis jest bezpłatny. Wypiszesz się jednym kliknięciem w wiadomości.