HIGH: noVNC sidecar containers exposed on host with no authentication #28

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

Issue

The noVNC sidecar containers expose VNC sessions directly on host ports with no authentication. The VNC password is hardcoded (per existing issue #4) and the ports are deterministically mapped to host ports in the 10000-15000 range.

Location

  • services/api/app/docker_manager.py:360-419 — start_novnc_sidecar()

Current Implementation

hash_val = int(hashlib.md5(session_id.encode()).hexdigest()[:8], 16)
base_port = 10000
novnc_port = base_port + (hash_val % 5000)

container = client.containers.run(
    image="docker.io/theasp/novnc:latest",
    ...
    ports={"8080/tcp": novnc_port},  # exposed on host
)

Risk

  • VNC sessions are directly accessible on host ports 10000-14999
  • No authentication on the noVNC web interface
  • VNC password is hardcoded ("devforge" per existing issue #4)
  • Ports are deterministic — anyone who knows the session ID can calculate the port
  • If the API is compromised, all VNC ports are exposed

Proposed Fix

  1. Don't expose noVNC ports on the host — proxy through the API instead
  2. Add authentication to noVNC sidecar
  3. Generate per-session random passwords (already partially addressed by existing VNC password endpoint)
  4. Use Docker networking (container name) instead of host port mapping

Priority: High
Type: Security

## Issue The noVNC sidecar containers expose VNC sessions directly on host ports with no authentication. The VNC password is hardcoded (per existing issue #4) and the ports are deterministically mapped to host ports in the 10000-15000 range. ## Location - `services/api/app/docker_manager.py:360-419` — `start_novnc_sidecar()` ## Current Implementation ```python hash_val = int(hashlib.md5(session_id.encode()).hexdigest()[:8], 16) base_port = 10000 novnc_port = base_port + (hash_val % 5000) container = client.containers.run( image="docker.io/theasp/novnc:latest", ... ports={"8080/tcp": novnc_port}, # exposed on host ) ``` ## Risk - VNC sessions are directly accessible on host ports 10000-14999 - No authentication on the noVNC web interface - VNC password is hardcoded ("devforge" per existing issue #4) - Ports are deterministic — anyone who knows the session ID can calculate the port - If the API is compromised, all VNC ports are exposed ## Proposed Fix 1. Don't expose noVNC ports on the host — proxy through the API instead 2. Add authentication to noVNC sidecar 3. Generate per-session random passwords (already partially addressed by existing VNC password endpoint) 4. Use Docker networking (container name) instead of host port mapping **Priority:** High **Type:** Security
Author
Owner

GSD VERIFY phase failed after 3 attempts.
═══ Gate: verify-passed (devforge#28) ═══
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  20:28:22
 Duration  750ms (transform 566ms, setup 0ms, import 141ms, tests 9ms, 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-21T03:28:24Z
Class: test-failure
Evidence: Verification failed: 1 failures
Git tag: devforge#28-gate-verify-fail-d6eb85bbe555 (use gate-retry after fixing)

GSD VERIFY phase failed after 3 attempts. ═══ Gate: verify-passed (devforge#28) ═══ 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  20:28:22  Duration  750ms (transform 566ms, setup 0ms, import 141ms, tests 9ms, 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-21T03:28:24Z Class: test-failure Evidence: Verification failed: 1 failures Git tag: devforge#28-gate-verify-fail-d6eb85bbe555 (use gate-retry after fixing)
Author
Owner

GSD RESEARCH: API call failed.
]11;?\API call failed after 3 retries: HTTP 429: Error code: 429 - {'status': 429, 'title': 'Too Many Requests'}

GSD RESEARCH: API call failed. ]11;?\API call failed after 3 retries: HTTP 429: Error code: 429 - {'status': 429, 'title': 'Too Many Requests'}
Mark closed this issue 2026-06-09 01:30:17 +00:00
Sign in to join this conversation.
No description provided.