{"record":{"id":"61bc32ed998742f5","repo":"JuliusBrussee/caveman","slug":"kms-decrypt-response-plaintext-exceeds-size-limit","errorCode":null,"errorMessage":"kms: decrypt response plaintext exceeds size limit","messagePattern":"kms: decrypt response plaintext exceeds size limit","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/kms/kms.go","lineNumber":265,"sourceCode":"\t}\n\tvar response struct {\n\t\tKeyID     string `json:\"key_id\"`\n\t\tPlaintext string `json:\"plaintext\"`\n\t}\n\tif err := c.call(ctx, envelope.Region, envelope.KeyID, \"decrypt\", map[string]string{\n\t\t\"ciphertext\": envelope.Ciphertext,\n\t}, &response); err != nil {\n\t\treturn nil, err\n\t}\n\tif response.KeyID != envelope.KeyID || response.Plaintext == \"\" {\n\t\treturn nil, errors.New(\"kms: invalid decrypt response\")\n\t}\n\tplaintext, err := base64.StdEncoding.DecodeString(response.Plaintext)\n\tif err != nil {\n\t\treturn nil, errors.New(\"kms: decrypt response plaintext is not valid base64\")\n\t}\n\tif len(plaintext) == 0 || len(plaintext) > maxPlaintextBytes {\n\t\treturn nil, errors.New(\"kms: decrypt response plaintext exceeds size limit\")\n\t}\n\treturn plaintext, nil\n}\n\n// ValidateProduction verifies real KMS configuration without network request.\nfunc ValidateProduction() error {\n\tif !runtimeenv.IsProduction() {\n\t\treturn nil\n\t}\n\t_, err := FromEnvironment()\n\treturn err\n}\n\n// ValidatePayloadProduction verifies the dedicated artifact-payload KEK is\n// configured. This is separate from ValidateProduction because control-plane\n// services that never handle artifacts need only the secrets key.\nfunc ValidatePayloadProduction() error {\n\tif !runtimeenv.IsProduction() {","sourceCodeStart":247,"sourceCodeEnd":283,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/kms/kms.go#L247-L283","documentation":"After base64-decoding the decrypt response, Decrypt checks the plaintext is non-empty and within maxPlaintextBytes. A decoded plaintext of zero bytes or exceeding the ceiling returns this error, defending against malicious or oversized envelopes.","triggerScenarios":"Server response whose decoded plaintext is empty or larger than the library's maxPlaintextBytes limit — e.g. decrypting an envelope produced with a different (larger) size policy, or a hostile/corrupted response.","commonSituations":"Data encrypted by another tool without size limits then decrypted here, attacker-supplied envelopes in a multi-tenant system, or version skew where this library's limit shrank relative to previously stored payloads.","solutions":["Check the plaintext size at encryption time; keep payloads under this library's maxPlaintextBytes","For larger data, encrypt a data-encryption key (envelope pattern) and store the bulk data encrypted elsewhere (see objectstore)","Confirm the envelope was produced by the same library version/policy"],"exampleFix":"// before\nif len(bigPayload) > limit { /* still encrypts elsewhere */ }\nct, _ := kmsClient.Encrypt(ctx, bigPayload)\n// after\nif len(bigPayload) > maxPlaintextBytes {\n\tdek, _ := kmsClient.Encrypt(ctx, smallDEK)\n\t// encrypt bigPayload with smallDEK\n}","handlingStrategy":"validation","validationCode":"if len(plaintext) == 0 || len(plaintext) > maxPlaintextBytes {\n\treturn fmt.Errorf(\"payload size %d outside encryptable range\", len(plaintext))\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Use the envelope pattern (KMS-encrypted DEK + locally encrypted bulk data) for large payloads","Enforce plaintext size limits at encryption time and at ingest","Keep library versions aligned so size policies match between encrypt and decrypt sides"],"tags":["kms","size-limit","response-validation"],"backgroundTag":"payload-too-large","analyzedSha":"3ee70a102609e550bd2e68004bf5990a9341c851","analyzedAt":"2026-09-20T15:53:39.229Z","contentChangedAt":"2026-09-20T15:53:39.229Z","schemaVersion":2},"datasetVersion":"2026-09-23T08:17:48.524Z"}