Skip to content

feat: v0.2.1 security hardening#1

Merged
msitarzewski merged 7 commits intomainfrom
release/0.2.1-security-hardening
Mar 13, 2026
Merged

feat: v0.2.1 security hardening#1
msitarzewski merged 7 commits intomainfrom
release/0.2.1-security-hardening

Conversation

@msitarzewski
Copy link
Owner

Summary

Comprehensive security hardening for the signaling server, client, and deployment infrastructure:

  • JWT Authentication: Room tokens (24h) prove peerId + roomId + role; invite tokens (4h) for authenticated link sharing. Only host/ops can generate invites.
  • WebSocket Rate Limiting: Sliding-window limiter (100 signaling/10s, 500 stream-chunk/10s), per-IP connection cap (10), 256KB maxPayload.
  • HTTP Security Headers: X-Content-Type-Options: nosniff, X-Frame-Options: DENY, Referrer-Policy: strict-origin-when-cross-origin on all responses.
  • CORS Allowlist: ALLOWED_ORIGINS env var for production; empty = allow all (dev mode).
  • Role-Based Access Control: Server-side enforcement — streaming, invite generation, and producer muting restricted to host/ops roles.
  • ICE Credential Protection: TURN credentials delivered via authenticated WebSocket (room-created/room-joined), removed from public /api/station API.
  • Icecast Proxy Hardening: Path sanitization (posix.normalize, block traversal, block /admin), CORS on proxy responses.
  • Icecast Entrypoint: Fail-fast credential validation — container won't start without passwords set.
  • Docker Security: Non-root user in Dockerfile, production Icecast bound to 127.0.0.1.
  • Input Validation: UUID v4 regex for peerId, from-field spoofing prevention.
  • Tests: Updated all peer IDs to valid UUID v4 format.

Files changed: 25 files, +767 −187

Area Files
New server/lib/auth.js
Server server.js, websocket-server.js, message-validator.js, static-server.js, icecast-listener-proxy.js, icecast-proxy.js
Client main.js, signaling-client.js, rtc-manager.js, icecast-streamer.js
Infra Dockerfile, docker-compose.yml, docker-compose.prod.yml, entrypoint.sh
Config .env.example, station-manifest.sample.json, station-manifest.production.json
Tests test-signaling.js, test-rooms.js
Docs memory-bank/ (5 files updated)

Test plan

  • npm test — all 18 tests pass with UUID v4 peer IDs
  • Manual: rate limiting triggers error after burst
  • Manual: connection limit (11th connection from same IP gets 4008)
  • Manual: create room → token returned, invite token flow works
  • Manual: guest cannot start stream or generate invites
  • Manual: /stream/../admin returns 403
  • Verify security headers in browser DevTools (Network tab)
  • Deploy with ALLOWED_ORIGINS set, verify CORS blocks other origins

🤖 Generated with Claude Code

msitarzewski and others added 7 commits March 13, 2026 14:28
Add comprehensive security hardening across server and client:

- JWT room tokens (24h) and invite tokens (4h) for authenticated access
- WebSocket rate limiting (100 signaling/10s, 500 stream/10s) and per-IP connection cap (10)
- HTTP security headers (X-Content-Type-Options, X-Frame-Options, Referrer-Policy)
- CORS origin allowlist via ALLOWED_ORIGINS env var
- Role-based access control: streaming/invites/muting restricted to host/ops
- ICE credentials (TURN) moved from public API to authenticated WebSocket flow
- Icecast proxy path sanitization (traversal + /admin blocked)
- Icecast entrypoint credential validation (fail-fast, no insecure defaults)
- Docker non-root user, UUID v4 peer ID validation, 256KB maxPayload
- Tests updated for UUID v4 validation, memory-bank updated

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…ture)

Tests were still pointing to localhost:8086 (old Python http.server).
Updated all 7 test files to use localhost:6736.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
WebRTC renegotiation takes longer on CI runners.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
…mp timeouts

The return-feed test depends on WebRTC renegotiation timing which is
inherently variable in headless CI. Added retry on failure, increased
timeouts, and set fail-fast:false so all matrix jobs run to completion.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
@msitarzewski msitarzewski merged commit 7a44f6d into main Mar 13, 2026
3 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant