crowdsecurity/crowdsec · critical

failed to generate nonce: %w

Error message

failed to generate nonce: %w

What it means

sealCookieV0 generates the random GCM nonce with crypto/rand.Read. This error means the OS CSPRNG failed, so the cookie cannot be sealed safely — without a fresh random nonce, AES-GCM nonce reuse would catastrophically break confidentiality and authenticity. The library fails closed.

Source

Thrown at pkg/appsec/challenge/crypto.go:145

	gcm, err := cipher.NewGCM(block)
	if err != nil {
		return "", fmt.Errorf("failed to create GCM: %w", err)
	}

	// Reject an over-limit envelope before marshaling it.
	maxPlaintext := maxCookieLen/4*3 - 1 - gcm.NonceSize() - gcm.Overhead()
	if plaintextLen := cookiePlaintextFixedHeaderLen + len(reason) + proto.Size(envelope); plaintextLen > maxPlaintext {
		return "", fmt.Errorf("%w: plaintext=%d > %d", ErrCookieTooLarge, plaintextLen, maxPlaintext)
	}

	envelopeBytes, err := proto.Marshal(envelope)
	if err != nil {
		return "", fmt.Errorf("failed to marshal challenge cookie proto: %w", err)
	}

	nonce := make([]byte, gcm.NonceSize())
	if _, err := rand.Read(nonce); err != nil {
		return "", fmt.Errorf("failed to generate nonce: %w", err)
	}

	// Build the plaintext: not_after_be8 || flags || reason_len_be || reason || envelope
	plaintext := make([]byte, 0, cookiePlaintextFixedHeaderLen+len(reason)+len(envelopeBytes))

	var notAfterBytes [8]byte
	binary.BigEndian.PutUint64(notAfterBytes[:], uint64(notAfter))
	plaintext = append(plaintext, notAfterBytes[:]...)

	plaintext = append(plaintext, flags)

	var reasonLenBytes [2]byte
	binary.BigEndian.PutUint16(reasonLenBytes[:], uint16(len(reason)))
	plaintext = append(plaintext, reasonLenBytes[:]...)

	plaintext = append(plaintext, []byte(reason)...)
	plaintext = append(plaintext, envelopeBytes...)

View on GitHub (pinned to 909b515798)

Solutions

  1. Inspect the wrapped OS error (errno) to identify the CSPRNG failure cause.
  2. Check the container/sandbox seccomp profile allows the getrandom syscall.
  3. Verify /dev/urandom is available and the host kernel is sane.
  4. Restart the process after fixing the environment; this is not retryable within the same call.

Example fix

// seccomp profile (docker/containerd): ensure getrandom is permitted
"syscalls": [
  {"names": ["getrandom"], "action": "SCMP_ACT_ALLOW"}
]
Defensive patterns

Strategy: retry

Try / catch

if err := errors.Is(err, randErr); err != nil {
    // log the OS-level cause; fix sandbox/CSPRNG; restart process
    return fmt.Errorf("cookie sealing unavailable, entropy failure: %w", err)
}

Prevention

When it happens

Trigger: Calling sealCookieV0 (via SealAllowlistCookie or ValidateChallengeResponse) when crypto/rand.Read returns an error — e.g. getrandom(2) blocked by a seccomp/sandbox profile, fd exhaustion, or a broken /dev/urandom in the container.

Common situations: Containers or sandboxes with restrictive seccomp profiles blocking getrandom; severely resource-starved hosts; unusual kernels or restricted environments (some hardened container runtimes).

Related errors


AI-assisted analysis of crowdsecurity/crowdsec@909b515798 (2026-09-06). Data as JSON: /api/errors/b1f1c466cbef9ab6. Report an issue: GitHub.