DNS-proxy repair selects the wrong sandbox's pod when one sandbox name is a prefix of another
- Dominant language
- TypeScript
- Stars
- 22.5k
- Forks
- 3.1k
- Avg merge
- 1d 1h
- Merged PRs (30d)
- 715
Description
## Investigation Summary
- `selectSandboxPod` (`src/lib/domain/dns/setup-proxy.ts`) matches a `kubectl get pods` line whenever the line merely *contains* the requested sandbox name, with no check that the remainder is a generated suffix.
- Reproduced directly: `selectSandboxPod("box1", "pod/box10-xyz12\n")` returns `"box10-xyz12"` — a pod for an unrelated sandbox — instead of `null`, even though no `box1` pod exists in the input at all.
- This selector is reachable from production code, not only the internal debug command: `nemoclaw connect` calls it via `repairSandboxInferenceRouteIfNeeded` → `runSetupDnsProxy` whenever the inference route is broken on the Kubernetes/k3s driver.
- A sibling lookup over the exact same `kubectl get pods -n openshell -o name` output, `isSandboxPodName` in `src/lib/tunnel/sandbox-gateway-stop.ts`, already requires an exact match or a generated-suffix (`^[a-z0-9]+$`) match — this file was never updated to match.
## Description
`nemoclaw connect`'s DNS-proxy repair path selects the target Kubernetes pod by checking whether a `kubectl get pods` line *contains* the requested sandbox name as a substring, rather than requiring an exact match or a properly-formed generated suffix. When one sandbox's name is a prefix of another sandbox's name (e.g. `box1` and `box10`), the repair can silently target the wrong sandbox's pod — installing the DNS forwarder, rewriting `/etc/resolv.conf`, and adding an `iptables` rule inside a different sandbox's network namespace than the one the user asked to connect to, while the sandbox actually being connected to gets no DNS proxy at all.
Expected: the selector should only match the exact sandbox name or that name followed by a `-`-delimited generated suffix, as `isSandboxPodName` in `src/lib/tunnel/sandbox-gateway-stop.ts` already does for the same kind of `kubectl get pods` output.
**Impact: security-boundary.** The repair path writes DNS-forwarder/`resolv.conf`/`iptables` state into a network namespace belonging to a sandbox other than the one the caller named, without that other sandbox's owner requesting it — a cross-sandbox isolation violation, not merely a wrong return value.
**Who hits this:** any user running the documented `nemoclaw connect` CLI command on the Kubernetes/k3s driver, whenever `repairSandboxInferenceRouteIfNeeded` (`src/lib/actions/sandbox/connect.ts`) falls back to its legacy DNS-proxy repair path (`runSetupDnsProxy` → `selectSandboxPod`) and another concurrently-running sandbox's name happens to be a prefix of the target sandbox's name (e.g. `box1` connecting while `box10` also exists). The user observes `connect` report success while the DNS repair actually landed in `box10`'s namespace and `box1` itself was never repaired.
## Reproduction Steps
1. `git clone` NemoClaw and open a Node REPL (or a small script) that imports `selectSandboxPod` from `src/lib/domain/dns/setup-proxy.ts`.
2. Call `selectSandboxPod("box1", "pod/box10-xyz12\n")`.
3. Observe it returns `"box10-xyz12"` instead of `null` — there is no pod named `box1` (or `box1-`) in the input, yet the function reports a match belonging to a different sandbox (`box10`).
4. In a live k3s/Kubernetes-driver deployment with two concurrently running sandboxes named e.g. `box1` and `box10`, running `nemoclaw box1 connect` while `box1`'s inference route is unhealthy would repair DNS inside `box10`'s pod instead.
## Environment
- OS: Ubuntu 24.04.4 LTS (x86_64)
- Hardware: x86_64 workstation
- Node.js: v22.23.1
- Docker: not installed in this environment (bug reproduced via direct unit-level execution of the pure selector function; no live Kubernetes cluster required to demonstrate the misselection)
- NemoClaw: reproduced against `main` at commit `b83c78e6693034967c16a5cd45f576b539b929d8`
Contributor guide
Research direction
Start in src/lib/domain/dns/setup-proxy.ts at selectSandboxPod and reproduce the box1 versus box10 example from the issue. Compare its matching behavior with isSandboxPodName in src/lib/tunnel/sandbox-gateway-stop.ts, then verify that exact names and names with generated suffixes match while prefix-only names do not; the connect path is reached through src/lib/actions/sandbox/connect.ts.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- kubernetes, typescript
- Domain
- cli, security
- Issue type
- Bug
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Activity status
- Active
- Clarity
- Clearly specified
- Newbie friendliness
- 85/100