Back to Blog
medium SEVERITY6 min read

Insecure WebSocket Vulnerability: Why WSS Should Always Replace WS

A medium-severity vulnerability was discovered in a JavaScript streaming application where insecure WebSocket (ws://) connections were being used instead of secure WebSocket (wss://) connections. This security gap could expose sensitive data to man-in-the-middle attacks, allowing attackers to intercept and manipulate real-time communication between clients and servers.

O
By Orbis AppSec
•Technically reviewed by Anupam Mediratta•Published March 6, 2026•Reviewed June 3, 2026

Answer Summary

This vulnerability is an insecure WebSocket connection (CWE-319: Cleartext Transmission of Sensitive Information) in a JavaScript streaming application, where `ws://` was used instead of `wss://`. The `ws://` protocol transmits data in plaintext over the network, making it trivially interceptable by any attacker with network access. The fix is straightforward: replace every `ws://` connection URL with `wss://`, which wraps the WebSocket handshake and all subsequent frames in TLS encryption, the same protection used by `https://` for standard HTTP traffic.

Vulnerability at a Glance

cweCWE-319
fixReplace ws:// with wss:// to enforce TLS-encrypted WebSocket connections
riskReal-time data intercepted or manipulated in transit by a network attacker
languageJavaScript
root causeWebSocket URL hardcoded with ws:// scheme, bypassing TLS encryption
vulnerabilityInsecure WebSocket Connection (ws:// instead of wss://)

Introduction: The Hidden Danger in Real-Time Communication

WebSockets have revolutionized how we build real-time applications—from chat systems and live dashboards to streaming services and collaborative tools. However, with great power comes great responsibility. A recently patched vulnerability in a streaming application serves as a critical reminder: using insecure WebSocket connections (ws://) instead of secure ones (wss://) can expose your users to serious security risks.

This vulnerability, classified as medium severity, was found in a JavaScript streaming record implementation. While it might seem like a simple oversight, the implications of transmitting data over unencrypted WebSocket connections can be severe, especially when handling sensitive user information or authentication tokens.

The Vulnerability Explained

What Are WebSockets?

WebSockets provide full-duplex communication channels over a single TCP connection, enabling real-time, bidirectional data exchange between clients and servers. Unlike traditional HTTP requests, WebSocket connections remain open, allowing for instant data transmission without the overhead of repeated handshakes.

The Security Gap: WS vs. WSS

The vulnerability stems from using the ws:// protocol instead of wss://:

  • ws:// - Unencrypted WebSocket connection (similar to HTTP)
  • wss:// - Encrypted WebSocket connection over TLS/SSL (similar to HTTPS)

When you use ws://, all data transmitted through the WebSocket connection travels in plain text. This means:

  1. No encryption: Data is readable by anyone who can intercept the network traffic
  2. No authentication: No guarantee you're connecting to the legitimate server
  3. No integrity checking: Data can be modified in transit without detection

How Could This Be Exploited?

An attacker positioned between the client and server (man-in-the-middle attack) could:

1. Eavesdropping

User → [Attacker listening] → Server
"password123" transmitted in plain text

The attacker captures sensitive information like authentication tokens, personal messages, or financial data.

2. Data Manipulation

// Original message from client
{ "action": "transfer", "amount": 100, "to": "user123" }

// Modified by attacker
{ "action": "transfer", "amount": 10000, "to": "attacker456" }

3. Session Hijacking

If authentication tokens are transmitted over insecure WebSockets, attackers can steal these credentials and impersonate legitimate users.

Real-World Attack Scenario

Imagine a live streaming application where users can interact with broadcasters:

// Vulnerable code
const ws = new WebSocket('ws://streaming-app.com/live');

ws.onopen = () => {
    // User sends authentication token
    ws.send(JSON.stringify({
        token: 'user_auth_token_12345',
        action: 'join_stream'
    }));
};

An attacker on the same public WiFi network could:
1. Intercept the authentication token
2. Use it to impersonate the user
3. Access private streams or perform actions on behalf of the victim
4. Inject malicious messages into the chat stream

The Fix: Upgrading to Secure WebSockets

The Solution

The fix is straightforward but critical: always use wss:// for WebSocket connections. Here's what the secure implementation looks like:

Before (Vulnerable):

// Insecure WebSocket connection
const socket = new WebSocket('ws://example.com/stream');

socket.onopen = function() {
    console.log('Connected to stream');
    socket.send(JSON.stringify({
        userId: getCurrentUserId(),
        sessionToken: getSessionToken()
    }));
};

socket.onmessage = function(event) {
    const data = JSON.parse(event.data);
    processStreamData(data);
};

After (Secure):

// Secure WebSocket connection with TLS/SSL
const socket = new WebSocket('wss://example.com/stream');

socket.onopen = function() {
    console.log('Securely connected to stream');
    socket.send(JSON.stringify({
        userId: getCurrentUserId(),
        sessionToken: getSessionToken()
    }));
};

socket.onmessage = function(event) {
    const data = JSON.parse(event.data);
    processStreamData(data);
};

// Add error handling for security
socket.onerror = function(error) {
    console.error('WebSocket error:', error);
    // Implement fallback or retry logic
};

Dynamic Protocol Selection

For applications that need to work in both development and production:

// Automatically use secure protocol in production
const protocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
const wsUrl = `${protocol}//${window.location.host}/stream`;
const socket = new WebSocket(wsUrl);

Better approach for production:

// Always prefer wss:// and only fall back for local development
const isLocalDev = window.location.hostname === 'localhost' || 
                   window.location.hostname === '127.0.0.1';
const protocol = isLocalDev ? 'ws:' : 'wss:';
const socket = new WebSocket(`${protocol}//${window.location.host}/stream`);

How This Solves the Problem

By using wss://:

  1. Encryption: All data is encrypted using TLS/SSL, making it unreadable to interceptors
  2. Server Authentication: SSL certificates verify you're connecting to the legitimate server
  3. Data Integrity: Cryptographic checksums ensure data hasn't been tampered with
  4. Compliance: Meets security standards and regulatory requirements (PCI DSS, HIPAA, GDPR)

Conclusion

The transition from ws:// to wss:// might seem like a minor change—just three characters—but it represents a fundamental shift in security posture. This vulnerability fix demonstrates that security isn't always about complex cryptographic implementations or sophisticated attack prevention; sometimes it's about making the right choice with the tools already available to us.

Key Takeaways:

  1. Never use ws:// in production environments where sensitive data is transmitted
  2. Encryption should be the default, not an afterthought
  3. Automated security scanning can catch these issues before they reach production
  4. Defense in depth: Secure WebSockets are just one layer; implement comprehensive security measures

As developers, we have a responsibility to protect our users' data. By enforcing secure WebSocket connections and following security best practices, we can build real-time applications that are both powerful and secure.

Remember: If you wouldn't send it over HTTP, don't send it over WS. Always choose WSS.


Have you found similar vulnerabilities in your codebase? Share your experiences and security practices in the comments below. Stay secure, and happy coding!

Prevention and further reading

Related Articles

critical

How Unbounded WebSocket Message Handling Causes Resource Exhaustion in Node.js and How to Fix It

The WebSocketCrossServerAdapter class in a popular Node.js WebSocket library lacked any rate limiting on inbound messages, allowing attackers to flood Redis nodes and WebSocket servers with high-volume traffic. The fix introduces a configurable `rateLimit` option that caps messages per connection per second, preventing resource exhaustion while preserving legitimate functionality.

critical

How a vulnerable websocket-driver dependency happens in Node.js lockfiles and how to fix it

A Trivy scan flagged `websocket-driver@0.7.4` in this repository's `bun.lock` as affected by CVE-2026-54466, a critical issue in a WebSocket protocol handler that parses untrusted HTTP upgrade requests and frame data. The fix upgrades the package to `0.7.5` and adds an explicit `websocket-driver` entry to the lockfile's override block so every transitive consumer — webpack-dev-server, sockjs, faye-websocket — resolves to the patched build instead of the pinned vulnerable one.

critical

How command injection happens in JavaScript dependency trees and how to fix it

A critical command injection vulnerability in websocket-driver 0.7.4 allowed attackers to execute arbitrary shell commands through unescaped line terminators in WebSocket protocol handling. The automated fix upgrades to version 0.7.5 and adds an explicit override in package.json to prevent dependency resolution from reverting to the vulnerable version.

high

How Denial of Service via Invalid Binary POST Requests happens in Socket.IO and how to fix it

A high-severity Denial of Service vulnerability (CVE-2026-59725) was discovered in engine.io versions prior to 6.6.7, where invalid binary POST requests could crash Socket.IO servers. The fix upgrades engine.io from 6.6.5 to 6.6.7, which includes improved validation for binary packet handling and prevents malformed requests from taking down real-time communication channels.

critical

How Unsandboxed Plugin Execution Happens in Node.js and How to Fix It

A critical vulnerability (CVE-2026-54466) was discovered in the `websocket-driver` dependency (version 0.7.4), which handles WebSocket protocol framing and I/O. The fix upgrades the package to version 0.7.5 via an npm override in `package.json` and an updated lockfile, closing a WebSocket frame-parsing flaw that could allow attackers to inject or manipulate WebSocket traffic. This dependency-level fix is essential because the vulnerable library sits in the application's dependency tree and proce

critical

How WebSocket Protocol Handler Vulnerabilities happen in Node.js Dependencies and how to fix it

A critical vulnerability (CVE-2026-54466) was discovered in websocket-driver version 0.7.4, a WebSocket protocol handler used in the dependency tree. The vulnerability allowed attackers to exploit flaws in WebSocket frame parsing, potentially leading to denial of service or protocol-level attacks. The fix upgraded websocket-driver to version 0.7.5, which patches the protocol handling vulnerabilities and hardens input validation for untrusted WebSocket frames.