GHSA-6j3h-rp73-6rvf

Suggest an improvement
Source
https://github.com/advisories/GHSA-6j3h-rp73-6rvf
Import Source
https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/11/GHSA-6j3h-rp73-6rvf/GHSA-6j3h-rp73-6rvf.json
JSON Data
https://api.osv.dev/v1/vulns/GHSA-6j3h-rp73-6rvf
Aliases
Published
2026-11-09T21:58:00Z
Modified
2026-11-09T22:15:03Z
Severity
  • 8.2 (High) CVSS_V3 - CVSS:3.1/AV:N/AC:H/PR:L/UI:N/S:C/C:H/I:H/A:N CVSS Calculator
Summary
Telepresence: Tunnel endpoint accepts caller-supplied session ID with no ownership proof — active client sessions hijackable
Details

Summary

The Traffic Manager Tunnel gRPC streaming endpoint accepts a session ID from the first bytes of the client-controlled message payload. No verification confirms the caller owns the session. An attacker supplying a valid active session ID receives a fully routed tunnel for that session, gaining the network routing capabilities of the legitimate Telepresence client. Tested on HEAD v2.28.0, commit b2231a4.

Details

The Tunnel handler reads identity from a client-provided binary payload rather than from a verified credential or prior authenticated gRPC call:

// cmd/traffic/cmd/manager/service.go:1057-1063
func (s *service) Tunnel(server grpc.BidiStreamingServer[...]) error {
    stream, err := tunnel.NewServerStream(ctx, tunnel.ClientToManager, server)
    return s.state.Tunnel(ctx, stream)  // stream.SessionID() is client-controlled
}

state.Tunnel looks up the session ID in the sessions map with no ownership proof:

// cmd/traffic/cmd/manager/state/state.go:698-703
func (s *State) Tunnel(ctx context.Context, stream tunnel.Stream) error {
    id := stream.SessionID()   // from client payload bytes
    if cs, ok := s.clients.Load(id); ok {
        return s.clientTunnel(ctx, cs, stream)  // full dialer granted
    }
    return grpcErrors.Errorf(codes.NotFound, ...)
}

The session ID is parsed from the wire message with no binding to the transport-level identity of the caller (pkg/tunnel/message.go:209-214).

Proof of Concept

Precondition: a valid active session ID (obtainable via ArriveAsClient, which has no auth either).

conn, _ := grpc.NewClient("traffic-manager.ambassador:8081",
    grpc.WithTransportCredentials(insecure.NewCredentials()))
mgr := rpc.NewManagerClient(conn)

tunnelStream, _ := mgr.Tunnel(ctx)

// Send StreamInfo with victim session ID in payload
tunnelStream.Send(&rpc.TunnelMessage{Payload: buildStreamInfo(victimSessionID, ...)})

// Traffic Manager routes tunnel traffic for victimSessionID
// through this attacker-controlled bidirectional stream

Impact

A caller supplying a valid session ID of an active Telepresence client obtains a tunnel endpoint for that session's network routing context. Session IDs are UUID4s, making cold brute-force impractical; exploitation materialises when session IDs are obtainable via log leakage or cluster-internal channels. Combined with the unauthenticated ArriveAsClient endpoint, an attacker can create their own sessions and pivot to impersonate active developer sessions.

Database specific
{
    "cwe_ids": [
        "CWE-639"
    ],
    "github_reviewed": true,
    "github_reviewed_at": "2026-11-09T21:58:00Z",
    "nvd_published_at": "2026-11-04T21:17:40Z",
    "severity": "HIGH"
}
References

Affected packages

Go / github.com/telepresenceio/telepresence/v2

Package

Name
github.com/telepresenceio/telepresence/v2
View open source insights on deps.dev
Purl
pkg:golang/github.com/telepresenceio/telepresence/v2

Affected ranges

Type
SEMVER
Events
Introduced
0 Unknown introduced version / All previous versions are affected
Fixed
2.31.0

Database specific

source
"https://github.com/github/advisory-database/blob/main/advisories/github-reviewed/2026/11/GHSA-6j3h-rp73-6rvf/GHSA-6j3h-rp73-6rvf.json"