T3 Code, wsTicket upgrade ignores Origin
T3 Code 61c3794c authenticateWebSocketUpgrade verifies a wsTicket without an Origin check. Cookie sessions with a hostile Origin are rejected. Cookie sessions with no Origin are accepted. SameSite=Lax. Labbed. No CVE yet.
- Name
- T3 Code, wsTicket upgrade ignores Origin
- Type
- 0-day analysis
- CVE
- n/a
- CVE Risk
- low
- Disclosure Status
- public
- Vendor
- Ping
- Affected
- T3 Code pingdotgg/t3code 61c3794c32b0eeebfac09add43e403618c65d2d7. Needs a live wsTicket or a cookie client that omits Origin.
- Published
- 03 Nov 2026
- Updated
- 03 Nov 2026
- Tags
- 0-day, t3code, csrf, origin, cwe-346, cwe-200, local
The ticket in the URL did not ask which site called.
I am @abraxas_null. The proof of concept is on GitHub: abraxas/t3code-websocket-ticket-origin (loopback client). The lab is lab/: run.sh, poc.py, harness.test.ts. Authorized lab only. Production authenticateWebSocketUpgrade on the Effect test layer. No live browser CSRF.
This is T3 Code commit 61c3794c. No CVE yet. CWE-346 / CWE-200. 3.1 Low (CVSS:3.1/AV:N/AC:H/PR:L/UI:R/S:U/C:L/I:L/A:N). Origin leftover. Ticket holder, or a cookie client that omits Origin.
A socket ticket in the URL does not care which website asked for it. Cookie sessions with a hostile Origin are rejected. Cookie sessions with no Origin header are accepted. Bearer tokens ignore Origin on purpose. The session cookie is SameSite=Lax, which is what currently stops a cross-site cookie WebSocket.
This is not unauthenticated /ws. This is not a cookie CSRF in current browsers when Origin is present.
Why this leftover, and what the audit overstated
GET /ws in ws.ts calls authenticateWebSocketUpgrade(request, "rpc"). If the query has wsTicket, EnvironmentAuth.ts verifies the ticket (and DPoP when bound) and returns without isBrowserOriginAllowed. Cookie fallback goes through authenticateRequest, which does call it for cookie credentials.
isBrowserOriginAllowed returns true when Origin is missing. Otherwise it requires same-origin Sec-Fetch-Site, a trusted app origin, or a host match against Host / X-Forwarded-Host. In-tree tests already accept cookie upgrades from the app's own origins, accept a missing Origin, and reject origin: null and a wrong port. Bearer upgrades succeed regardless of page origin.
The leftover is the ticket path and the missing-Origin cookie branch. Cookie plus hostile Origin is closed on this pin.
Pinning 61c3794c
Same audit pin. I copied the EnvironmentAuth test layer, minted a pairing cookie session and a wsTicket, and sent the Origin matrix through the production authenticator.
The skip list
I did not drive a real browser. SameSite=Lax is doing the CSRF job for cookies. I did not treat Bearer-from-anywhere as a leftover; that is the non-browser client path.
What an attacker can do
Needs a live wsTicket or a cookie the browser will attach.
| Privilege | Method / sink | Recon / integrity / availability | Lab-proven or inferred |
|---|---|---|---|
| Ticket upgrade with hostile Origin | authenticateWebSocketUpgrade wsTicket |
Integrity | Lab-proven. accepted, Origin https://evil.example, witness t3f04o6n1 |
| Cookie upgrade with no Origin | isBrowserOriginAllowed |
Integrity | Lab-proven. accepted |
| Bearer upgrade with hostile Origin | Authorization header | Integrity | Lab-proven. accepted |
| Negative control: cookie + hostile Origin | Origin other port | n/a | Lab-proven. ServerAuthInvalidCredentialError |
| Negative control: cookie + trusted Origin | same host | n/a | Lab-proven. accepted |
Stays closed on this leftover
| Axis | Method / sink | Why it is closed |
|---|---|---|
| Integrity | Cookie WebSocket from a random site that sends Origin | rejected; SameSite=Lax also withholds the cookie |
| Integrity | Unauthenticated /ws |
missing credential |
| Integrity | Cross-site cookie CSRF in current browsers | sameSite: "lax" in apps/server/src/auth/http.ts |
The lab
IOC cookie-missing-origin=accepted
IOC cookie-hostile-origin=rejected
IOC cookie-trusted-origin=accepted
IOC ticket-hostile-origin=accepted
IOC bearer-hostile-origin=accepted
IOC samesite=lax
SUCCESS T3-F04-WSORIGIN t3f04o6n1Wrong turns: reporting "no Origin check anywhere" for cookie upgrades.
The fix
Run isBrowserOriginAllowed on the ticket path, or bind tickets to the Origin that minted them. Treat a missing Origin as a failure for cookie credentials. Add an explicit Origin allowlist on the upgrade. Keep SameSite=Lax or Strict.
I am @abraxas_null. Site abraxaslabs.tech. GitHub abraxas. Mail abraxas.null@proton.me.