Security: API key exposed in query parameters #5

Closed
opened 2026-03-10 03:45:52 +00:00 by Mark · 25 comments
Owner

Issue

API keys are passed via query parameters (?api_key=...) which exposes them in:

  • Browser history
  • Server access logs
  • Referrer headers

Location

  • services/web/src/components/SessionView.tsx:89,117
  • services/web/src/components/PortManager.tsx:121-127
  • Multiple webview proxy endpoints

Current Implementation

const encodedKey = encodeURIComponent(key)
return `${API_BASE}/sessions/${sessionId}/webview/${port}?api_key=${encodedKey}`

Risk

  • Keys logged in proxy/access logs
  • Keys visible in browser history
  • Keys leaked via referrer to third-party sites

Proposed Solution

  1. Use HTTP-only cookies for webview access
  2. Use WebSocket for terminal (already does this)
  3. Implement session tokens with short expiry for webview access

Acceptance Criteria

  • Replace query param auth with cookie-based auth for webviews
  • Implement short-lived webview tokens
  • Ensure backward compatibility during transition
  • Audit all places where api_key is used in URL

Priority: High
Type: Security

## Issue API keys are passed via query parameters (`?api_key=...`) which exposes them in: - Browser history - Server access logs - Referrer headers ## Location - `services/web/src/components/SessionView.tsx:89,117` - `services/web/src/components/PortManager.tsx:121-127` - Multiple webview proxy endpoints ## Current Implementation ```typescript const encodedKey = encodeURIComponent(key) return `${API_BASE}/sessions/${sessionId}/webview/${port}?api_key=${encodedKey}` ``` ## Risk - Keys logged in proxy/access logs - Keys visible in browser history - Keys leaked via referrer to third-party sites ## Proposed Solution 1. Use HTTP-only cookies for webview access 2. Use WebSocket for terminal (already does this) 3. Implement session tokens with short expiry for webview access ## Acceptance Criteria - [ ] Replace query param auth with cookie-based auth for webviews - [ ] Implement short-lived webview tokens - [ ] Ensure backward compatibility during transition - [ ] Audit all places where api_key is used in URL **Priority:** High **Type:** Security
Author
Owner

6 references across SessionView.tsx and PortManager.tsx. Fix: move api_key from query param to Authorization: Bearer header on frontend, and update backend middleware to read from header instead. Moderate scope, tabling.

6 references across SessionView.tsx and PortManager.tsx. Fix: move api_key from query param to Authorization: Bearer header on frontend, and update backend middleware to read from header instead. Moderate scope, tabling.
Author
Owner

🤖 Claimed by gsd-issue-fixer-devforge-5 — starting work

🤖 Claimed by `gsd-issue-fixer-devforge-5` — starting work
Author
Owner

🤖 Claimed by gsd-issue-fixer-devforge-5 — starting work

🤖 Claimed by `gsd-issue-fixer-devforge-5` — starting work
Author
Owner

🤖 Claimed by gsd-issue-fixer-devforge-5 — starting work

🤖 Claimed by `gsd-issue-fixer-devforge-5` — starting work
Author
Owner

🤖 Claimed by gsd-issue-fixer-devforge-5 — starting work

🤖 Claimed by `gsd-issue-fixer-devforge-5` — starting work
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — claimed — starting pipeline

🤖 [`gsd-issue-fixer-devforge-5`] still working — claimed — starting pipeline
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — claimed — starting pipeline

🤖 [`gsd-issue-fixer-devforge-5`] still working — claimed — starting pipeline
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — claimed — starting pipeline

🤖 [`gsd-issue-fixer-devforge-5`] still working — claimed — starting pipeline
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — claimed — starting pipeline

🤖 [`gsd-issue-fixer-devforge-5`] still working — claimed — starting pipeline
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — research

🤖 [`gsd-issue-fixer-devforge-5`] still working — research
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — research

🤖 [`gsd-issue-fixer-devforge-5`] still working — research
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — research

🤖 [`gsd-issue-fixer-devforge-5`] still working — research
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — research

🤖 [`gsd-issue-fixer-devforge-5`] still working — research
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — plan

🤖 [`gsd-issue-fixer-devforge-5`] still working — plan
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — plan

🤖 [`gsd-issue-fixer-devforge-5`] still working — plan
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — plan

🤖 [`gsd-issue-fixer-devforge-5`] still working — plan
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — implement attempt 1

🤖 [`gsd-issue-fixer-devforge-5`] still working — implement attempt 1
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — implement attempt 1

🤖 [`gsd-issue-fixer-devforge-5`] still working — implement attempt 1
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — implement attempt 1

🤖 [`gsd-issue-fixer-devforge-5`] still working — implement attempt 1
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — plan

🤖 [`gsd-issue-fixer-devforge-5`] still working — plan
Author
Owner

GSD VERIFY phase failed after 3 attempts.
═══ Gate: verify-passed (devforge#5) ═══
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  14:33:52
 Duration  946ms (transform 764ms, setup 0ms, import 155ms, tests 15ms, environment 1ms)
Running linter...
✅ Lint clean
⚠️ No type checker discovered
No previous test result to compare

❌ GATE FAIL: verify-passed
- Tests failed with exit code 1
GATE FAIL: verify — blocked at 2026-05-27T21:33:55Z
Class: test-failure
Evidence: Verification failed: 1 failures
Git tag: devforge#5-gate-verify-fail-d8b03d138c09 (use gate-retry after fixing)

GSD VERIFY phase failed after 3 attempts. ═══ Gate: verify-passed (devforge#5) ═══ 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  14:33:52  Duration  946ms (transform 764ms, setup 0ms, import 155ms, tests 15ms, environment 1ms) Running linter... ✅ Lint clean ⚠️ No type checker discovered No previous test result to compare ❌ GATE FAIL: verify-passed - Tests failed with exit code 1 GATE FAIL: verify — blocked at 2026-05-27T21:33:55Z Class: test-failure Evidence: Verification failed: 1 failures Git tag: devforge#5-gate-verify-fail-d8b03d138c09 (use gate-retry after fixing)
Author
Owner

GSD VERIFY phase failed after 3 attempts.
═══ Gate: verify-passed (devforge#5) ═══
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  14:33:52
 Duration  1.02s (transform 806ms, setup 0ms, import 229ms, tests 27ms, 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-27T21:33:55Z
Class: test-failure
Evidence: Verification failed: 1 failures
Git tag: devforge#5-gate-verify-fail-d8b03d138c09 (use gate-retry after fixing)

GSD VERIFY phase failed after 3 attempts. ═══ Gate: verify-passed (devforge#5) ═══ 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  14:33:52  Duration  1.02s (transform 806ms, setup 0ms, import 229ms, tests 27ms, 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-27T21:33:55Z Class: test-failure Evidence: Verification failed: 1 failures Git tag: devforge#5-gate-verify-fail-d8b03d138c09 (use gate-retry after fixing)
Author
Owner

GSD VERIFY phase failed after 3 attempts.
═══ Gate: verify-passed (devforge#5) ═══
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  14:33:53
 Duration  850ms (transform 654ms, setup 0ms, import 201ms, tests 13ms, 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-27T21:33:55Z
Class: test-failure
Evidence: Verification failed: 1 failures
Git tag: devforge#5-gate-verify-fail-d8b03d138c09 (use gate-retry after fixing)

GSD VERIFY phase failed after 3 attempts. ═══ Gate: verify-passed (devforge#5) ═══ 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  14:33:53  Duration  850ms (transform 654ms, setup 0ms, import 201ms, tests 13ms, 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-27T21:33:55Z Class: test-failure Evidence: Verification failed: 1 failures Git tag: devforge#5-gate-verify-fail-d8b03d138c09 (use gate-retry after fixing)
Author
Owner

🤖 [gsd-issue-fixer-devforge-5] still working — implement attempt 1

🤖 [`gsd-issue-fixer-devforge-5`] still working — implement attempt 1
Author
Owner

GSD VERIFY phase failed after 3 attempts.
═══ Gate: verify-passed (devforge#5) ═══
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  14:43:00
 Duration  702ms (transform 517ms, setup 0ms, import 136ms, tests 12ms, 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-27T21:43:02Z
Class: test-failure
Evidence: Verification failed: 1 failures
Git tag: devforge#5-gate-verify-fail-eac6a8a87362 (use gate-retry after fixing)

GSD VERIFY phase failed after 3 attempts. ═══ Gate: verify-passed (devforge#5) ═══ 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  14:43:00  Duration  702ms (transform 517ms, setup 0ms, import 136ms, tests 12ms, 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-27T21:43:02Z Class: test-failure Evidence: Verification failed: 1 failures Git tag: devforge#5-gate-verify-fail-eac6a8a87362 (use gate-retry after fixing)
Mark 2026-06-09 04:56:00 +00:00
Sign in to join this conversation.
No description provided.