{"record":{"id":"f52e9e66c667c32e","repo":"golang/go","slug":"tls-short-read-from-rand","errorCode":null,"errorMessage":"tls: short read from Rand: ","messagePattern":"tls: short read from Rand: ","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"critical","filePath":"src/crypto/tls/handshake_client.go","lineNumber":107,"sourceCode":"\tif hello.vers > VersionTLS12 {\n\t\thello.vers = VersionTLS12\n\t}\n\n\tif c.handshakes > 0 {\n\t\thello.secureRenegotiation = c.clientFinished[:]\n\t}\n\n\thello.cipherSuites = config.cipherSuites(hasAESGCMHardwareSupport)\n\t// Don't advertise TLS 1.2-only cipher suites unless we're attempting TLS 1.2.\n\tif maxVersion < VersionTLS12 {\n\t\thello.cipherSuites = slices.DeleteFunc(hello.cipherSuites, func(id uint16) bool {\n\t\t\treturn cipherSuiteByID(id).flags&suiteTLS12 != 0\n\t\t})\n\t}\n\n\t_, err := io.ReadFull(config.rand(), hello.random)\n\tif err != nil {\n\t\treturn nil, nil, nil, errors.New(\"tls: short read from Rand: \" + err.Error())\n\t}\n\n\t// A random session ID is used to detect when the server accepted a ticket\n\t// and is resuming a session (see RFC 5077). In TLS 1.3, it's always set as\n\t// a compatibility measure (see RFC 8446, Section 4.1.2).\n\t//\n\t// The session ID is not set for QUIC connections (see RFC 9001, Section 8.4).\n\tif c.quic == nil {\n\t\thello.sessionId = make([]byte, 32)\n\t\tif _, err := io.ReadFull(config.rand(), hello.sessionId); err != nil {\n\t\t\treturn nil, nil, nil, errors.New(\"tls: short read from Rand: \" + err.Error())\n\t\t}\n\t}\n\n\tif maxVersion >= VersionTLS12 {\n\t\thello.supportedSignatureAlgorithms = supportedSignatureAlgorithms(minVersion, maxVersion)\n\t\thello.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithmsCert(minVersion, maxVersion)\n\t}","sourceCodeStart":89,"sourceCodeEnd":125,"githubUrl":"https://github.com/golang/go/blob/b6b368adc57c96c3151d224d172029f233ead2c3/src/crypto/tls/handshake_client.go#L89-L125","documentation":"Thrown by makeClientHello when io.ReadFull fails to read 32 random bytes for the ClientHello random field from config.rand(). By default, config.rand() returns crypto/rand.Reader, which reads from the operating system's CSPRNG (/dev/urandom on Linux, RtlGenRandom on Windows). A failure indicates the system entropy source is unavailable or a custom Rand reader is broken.","triggerScenarios":"config.rand() returns an error or premature EOF when asked for 32 bytes. This can happen with a custom config.Rand reader that does not implement io.ReadFull semantics, or when the OS entropy source (e.g., /dev/urandom) is inaccessible.","commonSituations":"Setting config.Rand to a broken or non-blocking-safe reader. Running in a heavily sandboxed container or chroot where /dev/urandom is not mounted. A FIPS module failure in fips-only mode. Extremely rare kernel entropy subsystem failures. Setting config.Rand to a deterministic reader for testing that returns fewer bytes than expected.","solutions":["Do not set config.Rand at all — let the library use crypto/rand.Reader by default","If using a custom Rand reader, ensure it implements io.Reader correctly and always returns the requested number of bytes or an error","Ensure /dev/urandom is available and readable in the runtime environment (check container/chroot/jail configuration)","If running in FIPS mode, verify the FIPS entropy module is properly initialized"],"exampleFix":"// before — broken custom Rand reader\nconfig := &tls.Config{Rand: brokenReader}\n// after — use default crypto/rand.Reader\nconfig := &tls.Config{} // Rand defaults to crypto/rand.Reader","handlingStrategy":"validation","validationCode":"// Do not set config.Rand unless you have a specific reason.\n// If you must, validate it can provide sufficient bytes:\nfunc validateRandReader(r io.Reader) error {\n    buf := make([]byte, 32)\n    n, err := io.ReadFull(r, buf)\n    if err != nil {\n        return fmt.Errorf(\"Rand reader failed: %w\", err)\n    }\n    if n != 32 {\n        return fmt.Errorf(\"Rand reader returned %d bytes, expected 32\", n)\n    }\n    return nil\n}","typeGuard":null,"tryCatchPattern":"// Prefer not setting config.Rand at all.\n// If a custom Rand is needed for testing, wrap it safely:\n//\n//   type safeRand struct{ r io.Reader }\n//   func (s *safeRand) Read(p []byte) (int, error) {\n//       return io.ReadFull(s.r, p) // guarantees full read or error\n//   }","preventionTips":["Never set config.Rand in production — use the default crypto/rand.Reader","Ensure /dev/urandom is mounted and readable in containers and sandboxes","For testing, use a deterministic reader that always returns the full requested length"],"tags":["tls","client-side","config","random","entropy","security"],"backgroundTag":null,"analyzedSha":"b6b368adc57c96c3151d224d172029f233ead2c3","analyzedAt":"2026-08-12T00:22:02.250Z","schemaVersion":2},"datasetVersion":"2026-08-12T12:31:55.035Z"}