Skip to content

Health endpoint returns 401 for trailing-slash variant /health/ (public probe marked unhealthy) #67

Description

@jonbaldie

Property

The /health endpoint is documented (openapi.yaml lines 17-36) as public — security: [], no authentication required — and returns 200. A health/liveness probe that reaches a trailing-slash variant (/health/) must receive the same public 200 (or at least not an authentication challenge). Load balancers, k8s liveness/readiness probes, and some HTTP clients normalize or append trailing slashes.

Counterexample

QUEUE_API_TOKEN=tok HOST=127.0.0.1 PORT=3992 deno run --allow-net --allow-env main.ts &
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3992/health     # 200  ✓
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3992/health/    # 401  ✗ — public endpoint returns "Unauthorized"
curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:3992/health//   # 401  ✗

A health check configured with a trailing slash gets 401 Unauthorized, so the probe marks a healthy service as down.

Root cause

The auth bypass in src/middleware.ts uses the same exact-match URLPattern as the router:

const HEALTH_PATTERN = new URLPattern({ pathname: "/health" });
// ...
if (HEALTH_PATTERN.exec(request.url)) {   // does NOT match "/health/"
    return next(request, info);
}

URLPattern({ pathname: "/health" }) does not match /health/ (or /health//). So /health/ falls through to the auth check, finds no Authorization header, and returns 401 — before the router ever runs (so it never reaches the 404 it would otherwise produce). The router's own /health route has the same exact-match behaviour, so even with a valid token /health/ yields 404, not 200.

Fix

Make the health bypass (and ideally the router) trailing-slash tolerant, e.g. match /health and /health/ explicitly, or normalize request.url's pathname by collapsing trailing slashes before matching. A targeted fix:

const HEALTH_PATTERN = new URLPattern({ pathname: "/health{/}?" });

Severity

Low: only affects the trailing-slash variant of one public endpoint. Real operational impact where probes are configured with /health/.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingready-for-agentFully specified and ready for an implementation agent

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions