JuliusBrussee/caveman · error

kms: decrypt response plaintext exceeds size limit

Error message

kms: decrypt response plaintext exceeds size limit

What it means

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.

Solutions

  1. Check the plaintext size at encryption time; keep payloads under this library's maxPlaintextBytes
  2. For larger data, encrypt a data-encryption key (envelope pattern) and store the bulk data encrypted elsewhere (see objectstore)
  3. Confirm the envelope was produced by the same library version/policy

Example fix

// before
if len(bigPayload) > limit { /* still encrypts elsewhere */ }
ct, _ := kmsClient.Encrypt(ctx, bigPayload)
// after
if len(bigPayload) > maxPlaintextBytes {
	dek, _ := kmsClient.Encrypt(ctx, smallDEK)
	// encrypt bigPayload with smallDEK
}
Defensive patterns

Strategy: validation

Validate before calling

if len(plaintext) == 0 || len(plaintext) > maxPlaintextBytes {
	return fmt.Errorf("payload size %d outside encryptable range", len(plaintext))
}

Prevention

When it happens

Trigger: 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.

Common situations: 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.

Understand the failure class

Background: payload too large / request exceeds maximum size: why libraries cap bytes and how to fix oversize payloads — this error's family across 50 libraries.

Related errors


AI-assisted analysis of JuliusBrussee/caveman@3ee70a1026 (2026-09-20). Data as JSON: /api/errors/61bc32ed998742f5. Report an issue: GitHub.

Appendix: source

Thrown at shared/platform/kms/kms.go:265

	}
	var response struct {
		KeyID     string `json:"key_id"`
		Plaintext string `json:"plaintext"`
	}
	if err := c.call(ctx, envelope.Region, envelope.KeyID, "decrypt", map[string]string{
		"ciphertext": envelope.Ciphertext,
	}, &response); err != nil {
		return nil, err
	}
	if response.KeyID != envelope.KeyID || response.Plaintext == "" {
		return nil, errors.New("kms: invalid decrypt response")
	}
	plaintext, err := base64.StdEncoding.DecodeString(response.Plaintext)
	if err != nil {
		return nil, errors.New("kms: decrypt response plaintext is not valid base64")
	}
	if len(plaintext) == 0 || len(plaintext) > maxPlaintextBytes {
		return nil, errors.New("kms: decrypt response plaintext exceeds size limit")
	}
	return plaintext, nil
}

// ValidateProduction verifies real KMS configuration without network request.
func ValidateProduction() error {
	if !runtimeenv.IsProduction() {
		return nil
	}
	_, err := FromEnvironment()
	return err
}

// ValidatePayloadProduction verifies the dedicated artifact-payload KEK is
// configured. This is separate from ValidateProduction because control-plane
// services that never handle artifacts need only the secrets key.
func ValidatePayloadProduction() error {
	if !runtimeenv.IsProduction() {

View on GitHub (pinned to 3ee70a1026)