Found by the Security reviewer during helmcode/nan-devops#389. Not introduced by that PR — the path predates it — but that PR doubles the number of nodes exposing it, so it should not stay unfiled.
The gap
The allow-internet-egress NetworkPolicy applied to member namespaces excludes 10.244/16, 10.245/16, 127/8, 10.8.0.0/24 and 172.16/12 from its egress CIDR — but not 10.10.0.0/24, the node VLAN. Verified identical across a sample of the member namespaces.
The host firewall accepts from 10.244/16 and 10.245/16 (pod CIDRs), and the inference backends answer an unauthenticated GET. So a pod in a member namespace can reach:
10.10.0.9:8090 and 10.10.0.5:8090 (whisper)
10.10.0.9:8880 and 10.10.0.5:8880 (kokoro)
- vLLM
:8001, TEI :8080 on the GPU nodes
directly — no API key, no rate limit, no SpendLogs row, no monthly cap. Every guard we have lives in LiteLLM, and this path does not go through it.
Why it matters more now
Before nan#86 the path existed against eu009. It now exists against eu005 too, because the second audio backend is deployed the same way. The fix does not get harder with two nodes, but the blast radius grows with each backend added this way.
Fix
Add 10.10.0.0/24 to the except list of the egress rule in the NetworkPolicy template (cloud-api generates it per namespace). One line in the template.
It is not a one-line rollout: it applies to ~585 existing member namespaces, so it needs the usual care — template change, verify on a fresh namespace, then a controlled sweep of the existing ones, watching for anything that legitimately talks to the VLAN.
Worth checking at the same time
Whether the backends should answer an unauthenticated request at all. They are OpenAI-shaped servers with no auth (speaches, Kokoro-FastAPI, vLLM), which is why the network boundary is the only control.
Context: helmcode/nan-devops#389, project_nan_host_firewall_2026_08_19.
Found by the Security reviewer during helmcode/nan-devops#389. Not introduced by that PR — the path predates it — but that PR doubles the number of nodes exposing it, so it should not stay unfiled.
The gap
The
allow-internet-egressNetworkPolicy applied to member namespaces excludes10.244/16,10.245/16,127/8,10.8.0.0/24and172.16/12from its egress CIDR — but not10.10.0.0/24, the node VLAN. Verified identical across a sample of the member namespaces.The host firewall accepts from
10.244/16and10.245/16(pod CIDRs), and the inference backends answer an unauthenticatedGET. So a pod in a member namespace can reach:10.10.0.9:8090and10.10.0.5:8090(whisper)10.10.0.9:8880and10.10.0.5:8880(kokoro):8001, TEI:8080on the GPU nodesdirectly — no API key, no rate limit, no
SpendLogsrow, no monthly cap. Every guard we have lives in LiteLLM, and this path does not go through it.Why it matters more now
Before nan#86 the path existed against eu009. It now exists against eu005 too, because the second audio backend is deployed the same way. The fix does not get harder with two nodes, but the blast radius grows with each backend added this way.
Fix
Add
10.10.0.0/24to theexceptlist of the egress rule in the NetworkPolicy template (cloud-api generates it per namespace). One line in the template.It is not a one-line rollout: it applies to ~585 existing member namespaces, so it needs the usual care — template change, verify on a fresh namespace, then a controlled sweep of the existing ones, watching for anything that legitimately talks to the VLAN.
Worth checking at the same time
Whether the backends should answer an unauthenticated request at all. They are OpenAI-shaped servers with no auth (speaches, Kokoro-FastAPI, vLLM), which is why the network boundary is the only control.
Context: helmcode/nan-devops#389,
project_nan_host_firewall_2026_08_19.