CVE-2026-65653 Overview
CVE-2026-65653 is a remote denial-of-service vulnerability in github.com/temporalio/tchannel-go, the Go implementation of Uber's TChannel RPC protocol. The library's fragment reader accepts call fragments that contain checksum metadata but no length-prefixed argument chunks. When such a malformed fragment arrives, the reader leaves its chunk slice empty and then unconditionally indexes the first element, triggering an unrecovered Go slice-bounds panic on a library-created dispatch goroutine. The panic terminates the entire hosting process. Any network peer that completes the standard initialization handshake can send the malformed frame as an initial call request, making services that expose the listener to untrusted peers directly reachable for remote crash attacks.
Critical Impact
A single malformed TChannel call fragment from an authenticated-or-unauthenticated network peer terminates the entire host process, causing service-wide outages. The impact is limited to availability with no confidentiality or integrity loss.
Affected Products
- github.com/temporalio/tchannel-go versions prior to v1.22.1
- Go applications embedding the affected TChannel library and exposing listeners to untrusted peers
- Temporal server deployments and downstream services that depend on the vulnerable fragment reader
Discovery Timeline
- 2026-09-21 - CVE-2026-65653 published to the National Vulnerability Database
- 2026-09-22 - Last updated in NVD database
Technical Details for CVE-2026-65653
Vulnerability Analysis
TChannel frames carry call arguments as length-prefixed chunks preceded by optional checksum metadata. The fragment reader in fragmenting_reader.go (lines 256-308) parses this checksum header, then reads argument chunks into a slice. When a frame contains valid checksum bytes but zero argument chunks, the parser accepts the frame as structurally valid and leaves the internal chunk slice empty. Subsequent logic then indexes element zero of that slice without a length check.
The resulting out-of-bounds slice access [CWE-129] raises a Go runtime panic on the dispatch goroutine spawned by the library itself. Because the goroutine is created inside tchannel-go, the calling application has no opportunity to install a recover() handler on the stack. The unrecovered panic propagates to the Go runtime, which terminates the process.
Root Cause
The root cause is missing input validation of an array index derived from attacker-controlled data. The fragment parser trusts that any frame containing a checksum header will also contain at least one argument chunk. No guard rejects an empty chunk set before the code path that dereferences chunks[0]. The patched code introduces errEmptyFragment = errors.New("peer fragment contained no chunks") and returns this error rather than panicking.
Attack Vector
Exploitation requires only network reachability to the TChannel listener. An attacker completes the standard TChannel initialization handshake, then sends a single callReq frame containing checksum metadata and zero argument chunks. No authentication, prior state, or user interaction is required. The malformed frame can be delivered as the very first call after handshake completion, so the attack is stateless and trivially scriptable.
// Patch: fragmenting_reader.go — new sentinel error added
errMismatchedChecksumTypes = errors.New("peer returned different checksum types between fragments")
errMismatchedChecksums = errors.New("different checksums between peer and local")
errChunkExceedsFragmentSize = errors.New("peer chunk size exceeds remaining data in fragment")
errEmptyFragment = errors.New("peer fragment contained no chunks")
errAlreadyReadingArgument = errors.New("already reading argument")
errNotReadingArgument = errors.New("not reading argument")
Source: GitHub Commit 0cb017f
// Patch: checksum.go — reject unknown checksum types with an error
import (
"errors"
"hash"
"hash/crc32"
"sync"
)
var checksumPools [checksumCount]sync.Pool
var errInvalidChecksumType = errors.New("peer sent an unknown checksum type")
Source: GitHub Commit 0cb017f
Detection Methods for CVE-2026-65653
Indicators of Compromise
- Unexpected process termination of Go binaries linking tchannel-go, with stderr containing runtime error: index out of range originating in fragmenting_reader.go
- Panic stack traces referencing readArgument, newInboundFragment, or handleCallReq on a goroutine created by the TChannel dispatcher
- Repeated short-lived TCP connections from a single remote peer immediately preceded by process exit or supervisor restart events
Detection Strategies
- Monitor Go application logs and container exit_code telemetry for abnormal termination correlated with inbound TChannel traffic on the listener port (default 7933 for Temporal services)
- Inspect packet captures on TChannel ports for callReq frames that declare a checksum type but carry a payload length inconsistent with any argument chunks
- Correlate crash-loop patterns across service replicas with a common source IP contacting the TChannel endpoint
Monitoring Recommendations
- Enable Go runtime crash reporting and forward panic stack traces to centralized logging for review
- Track connection churn and per-peer error rates on TChannel listeners; a single peer causing repeated process restarts is a strong signal
- Alert on Kubernetes CrashLoopBackOff or systemd restart counters spiking on hosts running Temporal or other tchannel-go consumers
How to Mitigate CVE-2026-65653
Immediate Actions Required
- Upgrade github.com/temporalio/tchannel-go to v1.22.1 or later and rebuild all dependent binaries
- Audit dependency graphs with go list -m all | grep tchannel-go to identify indirect consumers of the vulnerable library
- Restrict network exposure of TChannel listeners to trusted peers using firewall rules or service mesh policies until patched binaries are deployed
Patch Information
The fix is included in tchannel-go v1.22.1. The relevant remediation commits are 0cb017f, 1dcfa67, and 8d8ca17, discussed in Pull Request #14. The patches replace the panicking index access with explicit error returns for empty fragments and unknown checksum types.
Workarounds
- Place TChannel listeners behind an authenticating proxy or mTLS-terminating gateway that rejects unauthenticated peers before the handshake completes
- Apply network-layer access control lists to limit TChannel ports to known service identities within the cluster
- Deploy process supervisors (systemd, Kubernetes restart policies) as a stopgap to restore service after a crash, while recognizing this does not prevent repeated denial of service
# Update go.mod to pinned patched version and rebuild
go get github.com/temporalio/tchannel-go@v1.22.1
go mod tidy
go build ./...
# Verify the resolved version
go list -m github.com/temporalio/tchannel-go
Disclaimer: This content was generated using AI. While we strive for accuracy, please verify critical information with official sources.

