TCP tunnel payload is plaintext after the handshake #2
Reference in New Issue
Block a user
Delete Branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Severity: High
The control handshake is AES-GCM, but the actual forwarded TCP stream is copied in the clear over the client↔server connection. That contradicts the README (“end-to-end encryption”, “All traffic is encrypted using AES-GCM”) and is how people would actually use this (HTTP, databases, anything that is not already TLS).
What happens
handleTCPConnectionencrypts onlyPortForwardRequest, thenforwardDatacopies raw bytes both ways (internal/client/client.go).readRequestdecrypts that request, thenhandleTCPForward→forwardDatacopies raw bytes to the target (internal/server/server.go).listen_address(LAN, a VPS NIC, a mis-bound0.0.0.0:9000) sees the payload after the first length-prefixed blob.UDP packets are encrypted per datagram. TCP is not.
SSH-over-teleport is still SSH, so that use case is fine. Plain HTTP, Postgres, Redis, SMB, etc. are fully exposed on the tunnel port.
Suggested fix (describe-only, no PR)
Do not use raw
iocopy on the tunnel socket. Frame the data path the same way as the request:uint32length + ciphertext.forwardDataimplementations (client and server), both directions.Until that lands, treat teleport as an unencrypted TCP proxy with an encrypted handshake, and only forward protocols that already encrypt themselves (SSH, HTTPS). Do not advertise database/HTTP forwarding as “secure.”
Triaged as high. README overclaims; TCP payload is not AES-GCM. Next: frame+encrypt both forwardData impls. Not into PR #1. Until then only forward SSH/HTTPS. Queued for Ash after #1 is green.