A tunnel carried inside a secure WebSocket has exactly as much encryption as the client put into it, no more. The wss:// scheme says that TLS protects one connection on one hop. It says nothing about whether the bytes inside the WebSocket messages are separately protected, and that distinction decides who can read your traffic when something in the middle terminates TLS.

Two layers that look like a single one

A secure WebSocket is TLS with a WebSocket handshake performed over it, as RFC 6455 describes in its connection and security sections. The TLS layer authenticates the server and encrypts the stream, then the WebSocket layer frames whatever the application decides to send.

Those are two independent decisions, and a diagram that draws one padlock over the whole path hides the second. Ask who terminates the TLS connection. Then ask what the client places inside each message. Everything else about the deployment follows from those two answers.

Design A: the transport is the only encryption

In the simpler design, the client takes raw IP packets and wraps them in WebSocket messages. Nothing inside is encrypted, so the component holding the TLS session reads plaintext payloads. When that component is your own tunnel server, this is the intended endpoint and the design is coherent, because the server was always going to see the traffic.

It becomes a different arrangement when an inspection proxy sits on the path and terminates TLS with a certificate the client trusts. That proxy now holds the same plaintext the server would have held, and no amount of WebSocket framing changes it. The client's trust store decided this outcome long before the tunnel opened, because it chose to accept that certificate for that name. The proxy also sees the requested host and the size of each message, which is enough to fingerprint a lot of activity without decrypting anything further.

Design B: the payload carries its own keys

In the second design, the client encrypts and authenticates its packets with a VPN protocol that has its own peer identity and key exchange, then carries the result inside WebSocket messages. Terminating the outer TLS here exposes ciphertext, not traffic. The proxy can see message sizes and timing, and nothing else in the payload. That is a much smaller exposure, and it is still metadata worth naming in a review rather than waving away.

The inner protocol's own endpoints still see plaintext, which is the point of the arrangement and also its limit. If a component on the endpoint is authorized to read data before encryption or after decryption, the extra layer does not constrain it. Keys, and the software that handles them, remain the boundary that matters.

A VPN label, a familiar client icon or a marketing page is not evidence that this design exists. Reading the payload format is.

Trace where the plaintext actually appears

The URL scheme gives you one fact, so get the rest from the interfaces. Run the checks below in order, because each one narrows the next:

ss -tnp | grep -E ':(443|8443)\b'
ip -br link show type tun
openssl s_client -connect vpn.example.net:443 -servername vpn.example.net -brief
tcpdump -ni tun0 -c 5 -X

Start with the outer connection. One long-lived TCP session to the TLS port is what a WebSocket carrier looks like, and a second session to an unrelated host is worth explaining before you look any deeper. Then find the tunnel interface on the client, because a tun or tap device tells you the client is handling IP packets rather than proxying a single application stream.

The capture on the tunnel interface usually settles the payload question. Readable headers there mean the inner packets were never separately encrypted, while high-entropy payloads mean they were. Repeat the capture on the outer interface and compare the two: if both look random, the inner layer is doing work the outer one cannot undo.

Review the trust you actually granted

An installed corporate root certificate is a fact about the client's trust store, not a statement about what any proxy logs or inspects. Establish the deployed policy and the real connection path instead of inferring behavior from the presence of a CA.

On managed equipment, ask the administrator which component terminates TLS, whether the client validates a pinned certificate or a public one, and what the payload format is. Those three answers produce a finding you can defend later.

Write the result as a boundary rather than a verdict. "TLS terminates at the inspection proxy, and the inner payload is separately encrypted with keys held only by the endpoints" is a checkable statement that survives a change of vendor. "WebSockets are secure" does not.

Artiglyn mynjee