nginx/nginx · error
NGX_LOG_ALERT
NGX_LOG_ALERT
Error message
quic token buffer is too small
What it means
ngx_quic_new_token() encrypts the token plaintext (20-byte address hash, time_t expiry, retry flag, ODCID length + bytes, all bounded by NGX_QUIC_MAX_TOKEN_SIZE = 64) with AES-256-GCM into a caller-provided buffer; before touching crypto it verifies that IV (12 bytes) + plaintext + GCM tag (16 bytes) fits token->len, else it logs this ALERT and returns NGX_ERROR, which fails NEW_TOKEN / retry-token generation. Stock callers in ngx_event_quic_output.c pass a buffer of NGX_QUIC_TOKEN_BUF_SIZE (12 + 64 + 16 = 92), so a hit means a custom caller passed a smaller buffer, local patches changed sizes, or an unusual ABI (e.g. larger time_t).
Solutions
- Size token buffers to NGX_QUIC_TOKEN_BUF_SIZE and set token->len = NGX_QUIC_TOKEN_BUF_SIZE before the call
- Do not shrink or reshape token fields (time_t size, ODCID length cap) in local patches
- If stock nginx hits this on your platform, report it with ABI details (sizeof(time_t), NGX_QUIC_MAX_TOKEN_SIZE)
Example fix
/* before */
u_char buf[32];
ngx_str_t token = { 32, buf };
/* after */
u_char buf[NGX_QUIC_TOKEN_BUF_SIZE];
ngx_str_t token = { NGX_QUIC_TOKEN_BUF_SIZE, buf }; Defensive patterns
Strategy: validation
Validate before calling
if (token.len < (size_t) (NGX_QUIC_AES_256_GCM_IV_LEN + 20 + sizeof(time_t) + 2 + NGX_QUIC_MAX_CID_LEN + NGX_QUIC_AES_256_GCM_TAG_LEN)) {
/* grow the buffer before calling ngx_quic_new_token() */
} Type guard
#define ngx_quic_token_buf_ok(t) ((t)->len >= (size_t) NGX_QUIC_TOKEN_BUF_SIZE)
Try / catch
rc = ngx_quic_new_token(log, sa, socklen, key, &token, &odcid, exp, is_retry);
if (rc != NGX_OK) { /* logged as ALERT; skip NEW_TOKEN/retry for this connection */ } Prevention
- Always allocate token buffers as NGX_QUIC_TOKEN_BUF_SIZE (IV + max payload + tag)
- Keep token field sizes (time_t, ODCID cap) unchanged in local patches
- Unit-test custom token callers with the maximum-size ODCID
When it happens
Trigger: Third-party or patched code calling ngx_quic_new_token() with token->len < 12 + 20 + sizeof(time_t) + 2 + odcid->len + 16; local patches enlarging the ODCID or expiry fields; platforms with sizeof(time_t) > 8.
Common situations: Custom modules built into nginx that generate tokens; forks that resized token fields without resizing the buffer.
Related errors
AI-assisted analysis of nginx/nginx@3f6f7824d4 (2026-08-22).
Data as JSON: /api/errors/608fa86dd7ce0b8c.
Report an issue: GitHub.
Appendix: source
Thrown at src/event/quic/ngx_event_quic_tokens.c:75
p = ngx_cpymem(p, &exp, sizeof(time_t));
*p++ = is_retry ? 1 : 0;
if (odcid) {
*p++ = odcid->len;
p = ngx_cpymem(p, odcid->data, odcid->len);
} else {
*p++ = 0;
}
len = p - in;
cipher = EVP_aes_256_gcm();
iv_len = NGX_QUIC_AES_256_GCM_IV_LEN;
if ((size_t) (iv_len + len + NGX_QUIC_AES_256_GCM_TAG_LEN) > token->len) {
ngx_log_error(NGX_LOG_ALERT, log, 0, "quic token buffer is too small");
return NGX_ERROR;
}
ctx = EVP_CIPHER_CTX_new();
if (ctx == NULL) {
return NGX_ERROR;
}
iv = token->data;
if (RAND_bytes(iv, iv_len) <= 0
|| !EVP_EncryptInit_ex(ctx, cipher, NULL, key, iv))
{
EVP_CIPHER_CTX_free(ctx);
return NGX_ERROR;
}
token->len = iv_len;View on GitHub (pinned to 3f6f7824d4)