#547·surya

vLLM container is published on all interfaces (-p {port}:8000 ignores SURYA_INFERENCE_HOST)

Author: UrielSlaysCreated Aug 12, 2026Updated Aug 12, 2026

Summary: surya publishes its auto-spawned vLLM container with -p {port}:8000 — no host address — so Docker binds it to all host interfaces. On any machine that isn't behind a host firewall, an ordinary local OCR call opens an unauthenticated GPU inference endpoint to the LAN (and to a tailnet/VPN, if present).

Where: surya/inference/backends/vllm.py (0.22.1), the docker run argument construction:

python
"-p",
f"{port}:8000",

Why this binds publicly: Docker's own documentation states that when a container's ports are mapped without a specific host address, the daemon publishes to all host addresses (0.0.0.0 and [::]), and that publishing is "insecure by default" — https://docs.docker.com/engine/network/port-publishing/

Observed (surya 0.22.1, Docker 29.7.2, Windows 11 + WSL2, RTX 4090). Three ordinary read-only OCR calls, default config, no explicit server configured — each spawned a container reachable off-box:

bash
docker inspect  -> ports {"8000/tcp":[{"HostIp":"0.0.0.0","HostPort":"58677"},
                                      {"HostIp":"::","HostPort":"58677"}]}

http://<lan-ip>:58677/health       -> 200
http://<tailnet-ip>:58677/health   -> 200      (off-LAN)
http://127.0.0.1:58677/v1/models   -> 200, unauthenticated

SURYA_INFERENCE_AUTOSTART defaults to True, so this is the default path, not an opt-in one.

Why it's surprising: settings.py already carries SURYA_INFERENCE_HOST = "127.0.0.1". That value is the client dial address; the publish binding ignores it. A reader of the settings would reasonably conclude the server is loopback-scoped — it isn't.

Suggested fix — honour the existing host setting in the publish mapping:

python
"-p",
f"{settings.SURYA_INFERENCE_HOST}:{port}:8000",

That keeps the current behaviour for anyone who deliberately sets SURYA_INFERENCE_HOST=0.0.0.0, and makes the default local-only, matching what the setting already implies.

Prior art for the same remediation: googledatalab/datalab#786 changed run.sh to -p 127.0.0.1:host_port:container_port for exactly this reason.

Notes / non-claims:

  • This is a default-exposure report, not an exploit report. I'm not claiming a vulnerability in vLLM itself; the concern is that a private inference dependency is reachable off-host without the operator choosing that.
  • Workaround for anyone hitting this now: run your own server bound to loopback (docker run -p 127.0.0.1:PORT:8000 ...), then set SURYA_INFERENCE_URL and SURYA_INFERENCE_AUTOSTART=False. Verified working — attaches in seconds and spawns nothing.
  • Separately, and this one is our bug rather than surya's: a client killed by a caller-side timeout orphans the container that surya would otherwise tear down on exit. Worth knowing that fixing the bind narrows the exposure but doesn't remove orphans caused by the caller.