Skip to content

echo-session-ws-gateway: allowlist Origin check rejects requests missing Origin header #214

Closed

Description

@flyingrobots

Context: Follow-up from PR #176 (embedded dashboard / ws gateway).

Problem

crates/echo-session-ws-gateway/src/main.rs has origin_allowed(state, headers) that behaves like this when --allow-origin is configured:

  • if Origin header is present: allow only if it matches one of the configured origins
  • if Origin header is missing: deny (returns false)

This can cause unexpected 403s for:

  • non-browser clients that don't send Origin
  • (possibly) same-origin browser traffic depending on browser/header behavior

Code pointer: origin_allowed around line ~1156.

Why this matters

  • It's easy to configure --allow-origin intending “lock down cross-origin”, but accidentally lock out legitimate clients.
  • The embedded dashboard is served from the same binary, so it's important the default behavior is sane for “serve dashboard + connect WS”.

Options

  1. Allow missing Origin by default when --allow-origin is set (treat missing Origin as same-origin / non-browser and allow).
  2. Keep current strict behavior, but document it explicitly and/or add an opt-in flag like --require-origin / --deny-missing-origin.
  3. Hybrid: allow missing Origin only when the request Host matches one of a configured list (more complex).

Acceptance criteria

  • Decide intended semantics for missing Origin under --allow-origin.
  • Implement and document it in crates/echo-session-ws-gateway/README.md.
  • Add a small test (unit or e2e) that locks the behavior.

(Originally surfaced by CodeRabbit as an “outside diff range” note on PR #176.)

Activity

  1. flyingrobots commented on Jan 2, 2026

    @flyingrobots
    OwnerAuthor

    Quick repro notes

    1. Start the gateway with an allowlist (example):
    cargo run -p echo-session-ws-gateway -- \
      --listen 127.0.0.1:8090 \
      --allow-origin http://localhost:8090
    1. Requests with an Origin header should be accepted when it matches. You can validate the allowlist logic at least for HTTP endpoints like /api/metrics (even if WS is the main target):
    curl -i \
      -H "Origin: http://localhost:8090" \
      http://127.0.0.1:8090/api/metrics
    1. Requests without an Origin header currently get rejected when --allow-origin is set (today’s behavior):
    curl -i http://127.0.0.1:8090/api/metrics

    Expected (current): 403 (or otherwise denied)
    Desired (if we change semantics): 200

    1. For WebSocket specifically, you can also sanity-check missing-Origin behavior using a non-browser WS client that omits the header. For example with websocat (if installed):
    # no Origin header
    websocat -v ws://127.0.0.1:8090/ws
    
    # explicitly set Origin
    websocat -v -H="Origin: http://localhost:8090" ws://127.0.0.1:8090/ws

    The exact handshake result depends on the WS route, but the key is whether origin_allowed() blocks the request pre-handshake.

    Note: exact browser behavior around sending Origin can vary; this repro focuses on the concrete (and common) case of non-browser clients / missing header.

  2. added a commit that references this issue on Jan 2, 2026
  3. flyingrobots commented on Jan 2, 2026

    @flyingrobots
    OwnerAuthor

    Decision: keep strict (missing rejected) and document it clearly. Landed in PR #218.

  4. flyingrobots commented on Jan 2, 2026

    @flyingrobots
    OwnerAuthor

    Decision: keep --allow-origin strict (missing Origin rejected) and document it clearly. Landed in PR #218.

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 workingsecuritySecuritytoolingTooling/CI/CLI

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions