MEDIUM: WebSocket echo endpoint has no authentication #30

Closed
opened 2026-05-08 23:51:24 +00:00 by Mark · 2 comments
Owner

Issue

The /ws/echo WebSocket endpoint has no authentication at all. Anyone who can reach the API can connect to it.

Location

  • services/api/app/main.py:1240-1249

Current Implementation

@app.websocket("/ws/echo")
async def ws_echo(ws: WebSocket):
    """Legacy echo endpoint (kept for backwards compatibility)."""
    await ws.accept()
    try:
        while True:
            msg = await ws.receive_text()
            await ws.send_text(msg)
    except WebSocketDisconnect:
        return

Risk

  • Echo endpoint can be used for reflected amplification if WebSocket connections are abused
  • No rate limiting or authentication
  • Information disclosure if future versions echo different content

Proposed Fix

  1. Require API key authentication (via query param like other WebSocket endpoints)
  2. Or remove the endpoint if it's no longer needed

Priority: Medium
Type: Security

## Issue The `/ws/echo` WebSocket endpoint has no authentication at all. Anyone who can reach the API can connect to it. ## Location - `services/api/app/main.py:1240-1249` ## Current Implementation ```python @app.websocket("/ws/echo") async def ws_echo(ws: WebSocket): """Legacy echo endpoint (kept for backwards compatibility).""" await ws.accept() try: while True: msg = await ws.receive_text() await ws.send_text(msg) except WebSocketDisconnect: return ``` ## Risk - Echo endpoint can be used for reflected amplification if WebSocket connections are abused - No rate limiting or authentication - Information disclosure if future versions echo different content ## Proposed Fix 1. Require API key authentication (via query param like other WebSocket endpoints) 2. Or remove the endpoint if it's no longer needed **Priority:** Medium **Type:** Security
Author
Owner

GSD VERIFY phase failed after 3 attempts.
═══ Gate: verify-passed (devforge#30) ═══
Mode: Tier 1 (functional only)

GATE OK: All gates up to 'implement' pass
── Tier 1: Functional ────────────────────────────────
Running tests...
❌ Tests failed (exit 1)
 FAIL  services/web/src/utils/terminalUtils.test.ts > terminalUtils > decodeTerminalMessage > should return empty Uint8Array for Blob input in sync decoder
 FAIL  services/web/src/utils/terminalUtils.test.ts > terminalUtils > debug mode > should return false when debug is not enabled
 FAIL  services/web/src/utils/terminalUtils.test.ts > terminalUtils > debug mode > should return true when debug is enabled
 FAIL  services/web/src/utils/terminalUtils.test.ts > terminalUtils > debug mode > should disable debug mode
ReferenceError: localStorage is not defined
 ❯ services/web/src/utils/terminalUtils.test.ts:12:5
 10|  beforeEach(() => {
 11|  vi.restoreAllMocks();
 12|  localStorage.clear();
 |  ^
 13|  });
 14| 

⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/9]⎯

 Test Files  4 failed | 1 passed (5)
 Tests  6 failed | 4 passed (10)
 Start at  19:54:59
 Duration  748ms (transform 577ms, setup 0ms, import 154ms, tests 11ms, environment 1ms)
Running linter...
✅ Lint clean
⚠️ No type checker discovered
Previous test count: unknown

❌ GATE FAIL: verify-passed
- Tests failed with exit code 1
GATE FAIL: verify — blocked at 2026-05-21T02:55:01Z
Class: test-failure
Evidence: Verification failed: 1 failures
Git tag: devforge#30-gate-verify-fail-01e7293e8dbd (use gate-retry after fixing)

GSD VERIFY phase failed after 3 attempts. ═══ Gate: verify-passed (devforge#30) ═══ Mode: Tier 1 (functional only) GATE OK: All gates up to 'implement' pass ── Tier 1: Functional ──────────────────────────────── Running tests... ❌ Tests failed (exit 1)  FAIL  services/web/src/utils/terminalUtils.test.ts > terminalUtils > decodeTerminalMessage > should return empty Uint8Array for Blob input in sync decoder  FAIL  services/web/src/utils/terminalUtils.test.ts > terminalUtils > debug mode > should return false when debug is not enabled  FAIL  services/web/src/utils/terminalUtils.test.ts > terminalUtils > debug mode > should return true when debug is enabled  FAIL  services/web/src/utils/terminalUtils.test.ts > terminalUtils > debug mode > should disable debug mode ReferenceError: localStorage is not defined  ❯ services/web/src/utils/terminalUtils.test.ts:12:5  10|  beforeEach(() => {  11|  vi.restoreAllMocks();  12|  localStorage.clear();  |  ^  13|  });  14|  ⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯⎯[4/9]⎯  Test Files  4 failed | 1 passed (5)  Tests  6 failed | 4 passed (10)  Start at  19:54:59  Duration  748ms (transform 577ms, setup 0ms, import 154ms, tests 11ms, environment 1ms) Running linter... ✅ Lint clean ⚠️ No type checker discovered Previous test count: unknown ❌ GATE FAIL: verify-passed - Tests failed with exit code 1 GATE FAIL: verify — blocked at 2026-05-21T02:55:01Z Class: test-failure Evidence: Verification failed: 1 failures Git tag: devforge#30-gate-verify-fail-01e7293e8dbd (use gate-retry after fixing)
Mark closed this issue 2026-05-30 14:10:40 +00:00
Author
Owner

Fixed: Added API key check to /ws/echo endpoint, matching the auth pattern used by /ws/terminal/{session_id}. Requires api_key query parameter, validated against DEVFORGE_API_KEY env var.

Fixed: Added API key check to `/ws/echo` endpoint, matching the auth pattern used by `/ws/terminal/{session_id}`. Requires `api_key` query parameter, validated against `DEVFORGE_API_KEY` env var.
Sign in to join this conversation.
No description provided.