← research

1SEAL-2026-001: remote out-of-bounds write in aws-c-event-stream streaming decoder

high
CVSS 8.1 CWE-787 awslabs/aws-c-event-stream fixed in v0.6.0 2026-03-17

update 2026-03-19: severity revised from CRITICAL 9.8 to HIGH 8.1 based on new information from AWS. AWS services enforce server-side header name length limits, narrowing the remote attack surface to client-side and MITM scenarios. attack complexity raised to High due to memory layout prediction requirements for exploitation beyond crash. see updated severity and exploitation path sections.

summary

a remote out-of-bounds write vulnerability exists in the streaming decoder of aws-c-event-stream, the C library implementing Amazon's application/vnd.amazon.event-stream binary protocol. a crafted event-stream message overflows a fixed-size buffer and overwrites adjacent function pointers in the decoder struct, including the on_error callback. code analysis indicates the corrupted callback can be reached through the decoder's own error-handling path, creating conditions for potential control-flow hijack.

severity

HIGH — CVSS 3.1 Base Score: 8.1

Vector: AV:N/AC:H/PR:N/UI:N/S:U/C:H/I:H/A:H

CWE: CWE-787 (Out-of-bounds Write)

CVE: assigned by Amazon CNA. publication pending.

severity history: initially assessed as CRITICAL 9.8 (AV:N/AC:L/PR:N/UI:N/S:U/C:H/I:H/A:H). revised to HIGH 8.1 after AWS confirmed that affected services — including S3 Select, Kinesis, Transcribe Streaming, and Lambda Invoke with response streaming — enforce server-side header name length limits, preventing exploitation through these services. attack complexity raised from Low to High: exploitation beyond crash requires circumventing memory layout protections (ASLR, stack canaries, CFI) to predict the decoder struct layout.

affected versions

all versions of aws-c-event-stream prior to v0.6.0.

the library is a transitive dependency of the AWS Common Runtime (CRT) and is used by AWS SDKs for streaming operations including S3 Select, Kinesis, Transcribe Streaming, and Lambda Invoke with response streaming.

root cause

the event-stream wire format encodes header names with a single-byte length prefix (header_name_len). the aws_event_stream_streaming_decoder struct contains a fixed-size buffer:

uint8_t header_name[INT8_MAX]; // 127 bytes

the non-streaming parser (aws_event_stream_read_headers_from_buffer) validates that header_name_len does not exceed INT8_MAX (127) before copying. the streaming parser (s_read_header_name) does not — it calls memcpy with the raw header_name_len byte, which as a uint8_t can be 0–255.

this is a signed/unsigned confusion: the buffer is sized to INT8_MAX (127), but the length field is UINT8_MAX (255). the non-streaming path caught this; the streaming path did not.

exploitation path

when header_name_len exceeds 127, memcpy writes up to 128 bytes past the end of header_name into adjacent struct fields. the overflow reaches function pointers in the same struct:

  • state (decoder state machine function pointer)
  • on_error (error callback)
  • on_header (header callback)
  • on_complete (message complete callback)
  • on_payload (payload callback)

after the overflow, the decoder's state pointer is overwritten back to a valid address (s_read_header_type) by the normal state transition in s_read_header_name. however, on_error remains corrupted with attacker-controlled bytes.

the overflow also corrupts the message prelude. in the normal decoder flow, this would cause a CRC mismatch on the next validation, which in turn invokes on_error — now containing attacker-controlled bytes. this represents a theoretical control-flow hijack path through the decoder's own error handling.

the decoder_pump() function calls decoder->state() in a tight while loop, creating temporal coupling: corruption and potential callback invocation occur within the same call frame.

server-side mitigations: AWS has confirmed that all affected services — S3 Select, Kinesis, Transcribe Streaming, and Lambda Invoke with response streaming — enforce maximum header name length limits server-side. this prevents exploitation through normal AWS service usage. the remaining attack surface is: (1) a client parsing event-stream data from a compromised or malicious service endpoint, or (2) a man-in-the-middle modifying event-stream data in transit.

the PoC demonstrates a deterministic crash under ASAN/UBSAN at the memcpy overflow itself. the CRC-triggered corrupted callback path is a valid exploitation scenario based on code analysis but is not directly witnessed in the PoC logs. exploitability beyond crash (e.g., remote code execution) requires predicting the memory layout of the decoder struct to control the overwritten function pointer — dependent on build mitigations (ASLR, stack canaries, CFI) and the specific caller's stack layout.

fix

fixed in commit c741f95 (2026-03-04), released as v0.6.0.

the fix expands the header_name buffer from INT8_MAX (127) to UINT8_MAX (255), eliminating the out-of-bounds condition by construction. the fix also adds a header_value_len bounds check in the streaming path that was absent for an adjacent unreported surface.

users should update to aws-c-event-stream v0.6.0 or later. for SDK users: update the AWS CRT dependency. check your lock files — transitive dependencies may pin older versions.

timeline

date event
2026-03-04 reported to AWS Security via aws-security@amazon.com
2026-03-04 fix committed (c741f95) and released as v0.6.0
2026-03-10 disclosure coordination letter sent to AWS CVD team
2026-03-17 public disclosure (initially assessed CRITICAL 9.8)
2026-03-19 severity revised to HIGH 8.1 based on AWS service-side mitigation data and CNA assessment

credit

discovered by Oleh Konko (1seal) as part of a systematic audit of AWS open-source infrastructure.

references