WebSocket CSRF-Like Attacks for Bug Bounty Hunters
A malicious page can ask the browser to open a WebSocket to another origin. If the target authenticates the handshake with ambient cookies and does not validate Origin, the attacker's JavaScript may gain a bidirectional channel under the victim's session. People call this cross-site WebSocket hijacking, but thinking in CSRF-like terms helps: the browser supplies authority that the malicious site does not own.
It differs from ordinary CSRF because the attacker may read server messages through the socket, not merely trigger a blind action.
Capture the real handshake
Use the application normally and inspect the HTTP Upgrade request. Record the WebSocket URL, cookies, Origin, subprotocol, query tokens, and any first message that authenticates the connection. Some apps open an anonymous socket, then send a bearer token in JSON. A cross-site page cannot read a token protected inside target JavaScript, so cookie presence alone may not be enough.
Replay the handshake with these controlled changes:
- Replace
Originwith your test origin - Remove
Origin - Use an untrusted sibling subdomain
- Omit the subprotocol
- Reuse a URL token in a clean session
A command-line client accepting a forged Origin proves server behavior, but not browser exploitability. Build the final PoC in a current browser.
Start with a listener, not a dangerous command
Host a page on a domain you control:
const ws = new WebSocket("wss://target.example/socket");
ws.onmessage = event => console.log(event.data);
Check DevTools and your own account. If private notifications, profile data, or room history arrive, save one planted canary. If the protocol requires a subscribe message, copy only the message for your controlled channel.
For write impact, choose a reversible action such as updating a draft status or sending a message to your second account. Do not trigger trades, device controls, mass notifications, or support commands.
Message authorization still matters
An Origin bypass gives access to whatever the victim's socket can do. Separate that from object-level authorization inside messages. If {"action":"join","roomId":"B"} lets account A enter account B's private room, that is an authorization bug even from a same-origin client. If the cross-site page can only ping a public feed, impact is low.
Sockets often trust state established by an earlier message. Try sending an action before authentication, switching tenant IDs after subscription, and reconnecting with stale resume tokens. Keep these tests distinct so triage can reproduce each boundary.
SameSite cookies may block cross-site authentication, but “site” is broader than origin. A compromised sibling subdomain can still create a socket with same-site cookies in some deployments. Record exact cookie attributes and browser version.
Report browser reality
Show the malicious page's origin, successful handshake, victim cookies or other ambient credential, messages sent, private canary received, and one safe action. Explain interaction: must the victim merely visit your page, already be logged in, or click a button to pass popup restrictions?
Recommend strict Origin allowlisting at the handshake, explicit unforgeable connection tokens, SameSite cookies as backup, and authorization on every message. Do not rely on CORS headers; WebSocket handshake rules are different.
PortSwigger's cross-site WebSocket hijacking guide covers the core browser flow. Frame the report around the trust mistake: an attacker-controlled origin obtained a session-bound channel and could read or act through it.