{"record":{"id":"4a626a6cceea17b2","repo":"JuliusBrussee/caveman","slug":"kms-decrypt-response-plaintext-is-not-valid-base64","errorCode":null,"errorMessage":"kms: decrypt response plaintext is not valid base64","messagePattern":"kms: decrypt response plaintext is not valid base64","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"shared/platform/kms/kms.go","lineNumber":262,"sourceCode":"\t}\n\tif strings.TrimSpace(envelope.Ciphertext) == \"\" {\n\t\treturn nil, errors.New(\"kms: envelope ciphertext is empty\")\n\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","sourceCodeStart":244,"sourceCodeEnd":280,"githubUrl":"https://github.com/JuliusBrussee/caveman/blob/3ee70a102609e550bd2e68004bf5990a9341c851/shared/platform/kms/kms.go#L244-L280","documentation":"Decrypt validates the KMS response and base64-decodes response.Plaintext. When the server (or a tampering intermediary) returns a Plaintext string that is not valid standard base64, decoding fails and this error replaces the raw decode error to keep the failure non-leaky.","triggerScenarios":"KMS endpoint or an interceptor returning malformed/corrupted plaintext field, envelope KeyID matching but plaintext field mangled (e.g. URL-safe base64 or raw bytes instead of StdEncoding), proxy rewriting the response.","commonSituations":"Custom fake/mock KMS servers in tests emitting wrong base64 variant, middleware that re-encodes responses, or hitting the wrong API version/endpoint returning an unexpected payload shape.","solutions":["Verify the response comes from the real Scaleway endpoint (no proxies re-encoding the body)","If using a mock, ensure it encodes plaintext with base64.StdEncoding","Log the raw response (in a safe environment) to confirm the malformed field; report unexpected server payloads to Scaleway if genuine"],"exampleFix":"// mock fix\n// before\nresp.Plaintext = string(plaintext)\n// after\nresp.Plaintext = base64.StdEncoding.EncodeToString(plaintext)","handlingStrategy":"try-catch","validationCode":"// validate response before use (if you control the mock/producer)\nif _, err := base64.StdEncoding.DecodeString(resp.Plaintext); err != nil {\n\treturn fmt.Errorf(\"producer emitted invalid base64: %w\", err)\n}","typeGuard":"func isValidStdBase64(s string) bool {\n\t_, err := base64.StdEncoding.DecodeString(s)\n\treturn err == nil\n}","tryCatchPattern":"plaintext, err := client.Decrypt(ctx, envelope)\nif err != nil {\n\tif err.Error() == \"kms: decrypt response plaintext is not valid base64\" {\n\t\t// inspect/refresh envelope, alert on possible tampering\n\t}\n\treturn fmt.Errorf(\"decrypt: %w\", err)\n}","preventionTips":["Encode mock payloads with base64.StdEncoding, not RawURLEncoding","Avoid proxies/middleware that rewrite response bodies","Pin the KMS API endpoint and version"],"tags":["kms","base64","response-validation"],"backgroundTag":"unexpected-api-response-shape","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"}