Skip to content

fix(server): public endpoints stay public when --api-prefix is set#87

Merged
marksverdhei merged 1 commit into
htfrom
fix/server-http-api-prefix-public-endpoints
Jun 12, 2026
Merged

fix(server): public endpoints stay public when --api-prefix is set#87
marksverdhei merged 1 commit into
htfrom
fix/server-http-api-prefix-public-endpoints

Conversation

@marksverdhei

Copy link
Copy Markdown

Summary

Bug-hunt round 4 on `tools/server/server-http.cpp`. The api-key middleware's allowlist for public endpoints (`/health`, `/v1/health`, `/models`, `/v1/models`, `/`, `/index.html`, `/bundle.js`, `/bundle.css`) matched against `req.path` verbatim. With `--api-prefix /llama`, the routes register at `/llama/health` etc. (handlers attach to `path_prefix + path` in `server_http_context::{get,post}`), so `req.path` arrives as `/llama/health` and never matches the un-prefixed allowlist — health probes and the static webui assets then 401 under `--api-key`, defeating the point of marking them public.

Repro

```sh
llama-server --api-key foo --api-prefix /llama --model tiny.gguf
curl -s -o /dev/null -w '%{http_code}\n' http://localhost:8080/llama/health # was 401, now 200
```

Fix

Capture `path_prefix` into the middleware lambda alongside `api_keys` and strip it from `req.path` before the allowlist lookup. Three-line change in the middleware, plus the obvious test fixture wiring (`api_prefix` field on `ServerProcess` + health-probe path adapts to the prefix).

Test plan

  • `test_api_prefix_keeps_public_endpoints_public` — drives `/llama/health`, `/llama/v1/models`, `/llama/`, `/llama/bundle.js` with `--api-key` + `--api-prefix /llama` and asserts no 401.
  • `test_api_prefix_still_requires_key_for_private_routes` — guards the inverse: private endpoints under prefix MUST still 401 without a key.
  • All 20 security tests pass locally (was 18 before, my 2 added).
  • `ServerProcess.start()` health probe now uses `(api_prefix or "") + "/health"` so tests can actually use `api_prefix`.

🤖 Generated with Claude Code

Bug-hunt round 4 finding on tools/server/server-http.cpp.

The api-key middleware's allowlist (/health, /v1/health, /models,
/v1/models, /, /index.html, /bundle.js, /bundle.css) was matched
against req.path verbatim. With --api-prefix /llama, the routes are
registered at "/llama/health" etc. (handlers attach to
path_prefix + path in server_http_context::{get,post}), so req.path
arrives as "/llama/health" and never matches the un-prefixed
allowlist. Health probes and the static webui assets then 401 under
--api-key, defeating the point of marking them public.

Capture path_prefix into the middleware lambda and strip it from
req.path before the allowlist lookup.

Caller audit:
- Only public_endpoints lookup needs the strip; the api-key validity
  check itself is correct regardless of prefix.
- The unrelated bundle-of-tests fix in utils.py adapts the health
  poll in ServerProcess.start() so tests can actually use api_prefix.

Tests in test_security.py:
- test_api_prefix_keeps_public_endpoints_public — drives all 4
  prefix+public endpoints with --api-key + --api-prefix and asserts
  no 401.
- test_api_prefix_still_requires_key_for_private_routes — guards the
  inverse: private endpoints under prefix MUST still 401 without a key.

20/20 security tests pass locally (was 18 before).
@marksverdhei marksverdhei merged commit f217419 into ht Jun 12, 2026
7 of 12 checks passed
@marksverdhei marksverdhei deleted the fix/server-http-api-prefix-public-endpoints branch June 12, 2026 19:07
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant