{"id":"fb6b8c50b2cd5e54","repo":"gofiber/fiber","slug":"failed-to-decrypt-ciphertext-w","errorCode":null,"errorMessage":"failed to decrypt ciphertext: %w","messagePattern":"failed to decrypt ciphertext: %w","errorType":"http","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"middleware/encryptcookie/utils.go","lineNumber":89,"sourceCode":"\t}\n\n\tblock, err := aes.NewCipher(keyDecoded)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create AES cipher: %w\", err)\n\t}\n\n\tgcm, err := cipher.NewGCMWithRandomNonce(block)\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to create GCM mode: %w\", err)\n\t}\n\n\tif len(enc) < gcm.NonceSize()+gcm.Overhead() {\n\t\treturn \"\", ErrInvalidEncryptedValue\n\t}\n\n\tplaintext, err := gcm.Open(nil, nil, enc, []byte(name))\n\tif err != nil {\n\t\treturn \"\", fmt.Errorf(\"failed to decrypt ciphertext: %w\", err)\n\t}\n\n\treturn string(plaintext), nil\n}\n\n// GenerateKey returns a random string of 16, 24, or 32 bytes.\n// The length of the key determines the AES encryption algorithm used:\n// 16 bytes for AES-128, 24 bytes for AES-192, and 32 bytes for AES-256-GCM.\nfunc GenerateKey(length int) string {\n\tif length != 16 && length != 24 && length != 32 {\n\t\tpanic(ErrInvalidKeyLength)\n\t}\n\n\tkey := make([]byte, length)\n\n\tif _, err := rand.Read(key); err != nil {\n\t\tpanic(err)\n\t}","sourceCodeStart":71,"sourceCodeEnd":107,"githubUrl":"https://github.com/gofiber/fiber/blob/9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c/middleware/encryptcookie/utils.go#L71-L107","documentation":"Returned by DecryptCookie (utils.go:87-89) when gcm.Open fails to authenticate and decrypt. GCM is authenticated encryption, so this fires on ANY of: wrong key, tampered ciphertext, or wrong associated data (the cookie name is passed as AAD at line 87).","triggerScenarios":"Decrypting with a different key than was used to encrypt; the cookie name passed to DecryptCookie differs from the name passed to EncryptCookie (AAD mismatch); client/server key rotation mismatch; ciphertext modified by a proxy or attacker; partial cookie truncation that survived the length check at line 83.","commonSituations":"Rotating the encryption key without a migration window; renaming the cookie between Encrypt and Decrypt calls; deploying a new key to only some instances behind a load balancer; users on old cookies after a key change.","solutions":["Verify the cookie NAME passed to DecryptCookie matches the one passed to EncryptCookie (it is used as GCM additional authenticated data).","Verify the KEY is identical across all instances and identical to the one used at encryption time — check env/config drift.","On key rotation, keep the old key around and try DecryptCookie with each until one succeeds, then re-encrypt with the new key.","Treat a decrypt failure as 'invalid session' and re-issue, never as a 500."],"exampleFix":"// before\nv, err := encryptcookie.DecryptCookie(\"sess\", c.Cookies(\"sess\"), key)\nif err != nil { return err }\n\n// after — AAD (name) must match the encryption name; fall through on failure\nv, err := encryptcookie.DecryptCookie(\"sess\", c.Cookies(\"sess\"), key)\nif err != nil {\n    // either tampered or encrypted under an old key — drop and re-issue\n    return c.Next()\n}","handlingStrategy":"try-catch","validationCode":null,"typeGuard":null,"tryCatchPattern":"// try current key, then any prior key for smooth rotation\nplaintext, err := tryDecrypt(name, raw, currentKey)\nif err != nil {\n    for _, old := range oldKeys {\n        if p, e := tryDecrypt(name, raw, old); e == nil {\n            plaintext = p\n            err = nil\n            break\n        }\n    }\n}\nif err != nil {\n    // tampered or unknown key — drop and re-issue\n    return c.Next()\n}","preventionTips":["Keep the cookie NAME identical between encrypt and decrypt (it is the GCM AAD).","Maintain a rolling list of accepted keys during rotation.","Never expose decrypt failures to the end user — always re-issue."],"tags":["crypto","gcm","cookie","encryptcookie","authentication"],"analyzedSha":"9a4c7e57fe0b080a04235d28a4b0d2b4b353d58c","analyzedAt":"2026-08-04T21:44:03.395Z","schemaVersion":2}