{"record":{"id":"3946ec7acf183f13","repo":"ory/hydra","slug":"plaintext-too-large","errorCode":null,"errorMessage":"plaintext too large","messagePattern":"plaintext too large","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"aead/xchacha20.go","lineNumber":43,"sourceCode":"\nfunc NewXChaCha20Poly1305(d Dependencies) *XChaCha20Poly1305 {\n\treturn &XChaCha20Poly1305{d}\n}\n\nfunc (x *XChaCha20Poly1305) Encrypt(ctx context.Context, plaintext, additionalData []byte) (string, error) {\n\tkey, err := encryptionKey(ctx, x.d, chacha20poly1305.KeySize)\n\tif err != nil {\n\t\treturn \"\", err\n\t}\n\n\taead, err := chacha20poly1305.NewX(key)\n\tif err != nil {\n\t\treturn \"\", errors.WithStack(err)\n\t}\n\n\t// Make sure the size calculation does not overflow.\n\tif len(plaintext) > math.MaxInt-aead.NonceSize()-aead.Overhead() {\n\t\treturn \"\", errors.WithStack(fmt.Errorf(\"plaintext too large\"))\n\t}\n\n\tnonce := make([]byte, aead.NonceSize(), aead.NonceSize()+len(plaintext)+aead.Overhead())\n\t_, err = cryptorand.Read(nonce)\n\tif err != nil {\n\t\treturn \"\", errors.WithStack(err)\n\t}\n\n\tciphertext := aead.Seal(nonce, nonce, plaintext, additionalData)\n\treturn base64.URLEncoding.EncodeToString(ciphertext), nil\n}\n\nfunc (x *XChaCha20Poly1305) Decrypt(ctx context.Context, ciphertext string, aad []byte) (plaintext []byte, err error) {\n\tmsg, err := base64.URLEncoding.DecodeString(ciphertext)\n\tif err != nil {\n\t\treturn nil, errors.WithStack(err)\n\t}\n","sourceCodeStart":25,"sourceCodeEnd":61,"githubUrl":"https://github.com/ory/hydra/blob/4174065ffb052799890f7480f5360a877a67ffc1/aead/xchacha20.go#L25-L61","documentation":"Encrypt computes the ciphertext size as plaintext length + nonce size + Poly1305 overhead and guards the addition against integer overflow before allocating. A plaintext larger than math.MaxInt minus these fixed overheads cannot be safely encrypted, so Encrypt rejects it up front.","triggerScenarios":"Calling Encrypt with a plaintext whose length exceeds math.MaxInt - chacha20poly1305.NonceSizeX - overhead (practically an enormous buffer, near the platform max int).","commonSituations":"Accidentally passing a streamed file read entirely into memory; a bug where an unbounded/uninitialized buffer is encrypted; 32-bit builds where MaxInt is small enough that large request bodies trip the check.","solutions":["Reduce the plaintext size; do not encrypt arbitrary-size payloads with AEAD — encrypt a content key instead and use streaming encryption for the payload.","Split large data into chunks encrypted independently.","If the input comes from user uploads, enforce a size limit before calling Encrypt.","Fix code paths that read unbounded input into a single byte slice."],"exampleFix":"// before\nblob, _ := io.ReadAll(r.Body)\nenc, err := x.Encrypt(ctx, blob)\n\n// after\nif r.ContentLength > maxPayload { http.Error(w, \"too large\", 413); return }\nblob, _ := io.ReadAll(io.LimitReader(r.Body, maxPayload))\nenc, err := x.Encrypt(ctx, blob)","handlingStrategy":"validation","validationCode":"const maxPlaintext = 1 << 20 // choose a sane app-level limit\nif len(plaintext) > maxPlaintext {\n    return fmt.Errorf(\"payload too large to encrypt: %d bytes\", len(plaintext))\n}","typeGuard":null,"tryCatchPattern":"enc, err := x.Encrypt(ctx, plaintext)\nif err != nil && strings.Contains(err.Error(), \"plaintext too large\") {\n    return nil, ErrPayloadTooLarge\n}","preventionTips":["Enforce application-level size limits before encrypting.","Encrypt symmetric content keys, not raw large payloads; use streaming AEAD for big data.","Avoid io.ReadAll on untrusted input destined for encryption.","Be extra careful with plaintext sizes on 32-bit platforms."],"tags":["encryption","aead","size-limit"],"backgroundTag":"plaintext-too-large","analyzedSha":"4174065ffb052799890f7480f5360a877a67ffc1","analyzedAt":"2026-09-03T14:52:41.581Z","contentChangedAt":"2026-09-03T14:52:41.581Z","schemaVersion":2},"datasetVersion":"2026-09-10T17:17:09.494Z"}