Skip to content

security: Restrict WebSocket CORS from wildcard to trusted origins #189

@Xhristin3

Description

@Xhristin3

Problem Statement

The StreamsGateway WebSocket namespace is configured with cors: { origin: "*" } at api/src/gateways/streams.gateway.ts:55. This allows any website on the internet to open a WebSocket connection to the gateway, perform JWT authentication, and subscribe to stream events. This enables Cross-Site WebSocket Hijacking (CSWSH) attacks where a malicious site opens a WebSocket to the victim's backend using the victim's credentials.

Evidence

// api/src/gateways/streams.gateway.ts:54-55
@WebSocketGateway({
  namespace: "/streams",
  cors: { origin: "*" },
})

The REST API correctly uses origin: process.env.CORS_ORIGIN || "http://localhost:3000" in api/src/main.ts:34. The WebSocket gateway should follow the same pattern.

Impact

A malicious website can open a WebSocket connection to wss://api.xstreamroll.io/streams, authenticate with the victim's JWT (obtained via XSS or cookie theft), and subscribe to all stream events. The attacker can also emit messages to the server (e.g., subscribe/unsubscribe to arbitrary streams) and potentially flood the victim's socket with events.

Proposed Solution

Replace cors: { origin: "*" } with cors: { origin: process.env.CORS_ORIGIN || "http://localhost:3000" }. For WebSocket connections, also configure credentials: true to match the REST API CORS settings if cookie-based auth is used on the WebSocket handshake.

Technical Requirements

  • Must use the same CORS_ORIGIN env var as the REST API
  • Must support multiple origins in production if needed (array of allowed origins)
  • Must not break local development (localhost:3000)

Acceptance Criteria

  • WebSocket connections from unauthorized origins are rejected
  • WebSocket connections from the configured CORS_ORIGIN succeed
  • Local development still works (localhost:3000)
  • REST API CORS behavior is unchanged
  • All existing tests pass

File Map

  • api/src/gateways/streams.gateway.ts:55 — change CORS origin

Dependencies

  • Related: REPO-001 (JWT auth must work on WebSocket too)

Testing Strategy

  • Manual: Verify WebSocket connection rejected from different origin
  • Manual: Verify WebSocket connection accepted from same origin
  • Consider adding a WebSocket integration test

Security Considerations

This is a defense-in-depth measure. Even with proper JWT auth (REPO-001), a wildcard CORS policy allows any origin to present a valid JWT and interact with the WebSocket gateway. The origin check prevents the browser-based CSWSH attack vector entirely.

Definition of Done

  • Code implemented and peer-reviewed
  • Tests written and passing (unit + integration where applicable)
  • Documentation updated if behavior changed
  • No new linting errors or type errors introduced
  • Security considerations addressed
  • PR linked to this issue and merged

Labels: security, quick win
Priority: High
Difficulty: Beginner
Estimated Effort: 0.5h
Milestone: v1.0-alpha


Labels: security,quick win
Priority: High | Difficulty: Beginner | Estimated Effort: 0.5h
Backlog ID: REPO-006

Metadata

Metadata

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial CampaignCampaign: Official Campaignquick winsecuritySecurity related issues

Type

No type
No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions